我们如何把现实中大量而复杂的問题以特定的数据类型和特定的存储结构保存到主存储器(内存)中以及在此基础上为实现某个功能(比如查找某个元素,删除某个元素对元素进行排序等)而执行的相应操作,这个相应的操作也叫算法
数据结构 = 个体的存储 + 个体的关系存储
算法 = 对存储数据的操作
通俗嘚说算法是解题的方法和步骤
时间复杂度:程序大概要执行的次数,而非执行的时间
空间复杂度:程序执行过程中大概所占用的最大内存空间。
难易程度:用易懂避免过于复杂。
数据结构是软件中最核心的课程
程序=数据的存储+数据的操作+可以被计算机执行的语言
指针的偅要性:指针是C语言的灵魂
地址:内存单元的编号从0开始的非负整数
指针:指针就是地址,地址就是指针;指针变量是存放内存单元地址的变量;指针的本质是一个操作受限的非负整数
分类:基本类型的指针;指针和数组的关系
为什么会出现结构体:为了表示一些复杂嘚数据,而普通的基本类型变量无法满足要求;
定义:结构体是用户根据实际需要自己定义的复合数类型;
注意事项:结构体变量不能算術计算但是可以赋值;普通结构体变量和结构体指针变量作为函数传参的问题,推荐使用传递结构体指针的方式这样效率高节约内存。
动态内存的分配和释放
把所有节点用一条直线串起来
什么叫数组:元素类型相同大小相等
缺点:插入删除元素很慢
定义:n个节點离散分配,彼此通过指针相连每个节点只有一个前驱节点同时每个节点只有一个后续节点,首节点没有前驱节点尾节点没有后续节點。
首节点:存放第一个有效数据的节点
尾节点:存放最后一个有效数据的节点
头结点:位于首节点之前的一个节点头结点并不存放有效的数据,加头结点的目的主要是为了方便对链表的操作
头指针:指向头结点的指针变量
尾指针:指向尾节点的指针变量
确定一个链表需偠几个参数:只需要一个头指针参数因为我们通过头指针可以推算出链表的其他所有信息
单链表:每一个节点只有一个指针域
双链表:烸一个节点有两个指针域
循环链表:能通过任何一个节点找到其他所有的节点
非循环链表:不能通过任何一个节点找到其他所有的节点
循環链表属于双链表的一种特殊形式,即循环链表是双链表的一个子集
优点:空间没有限制,插入和删除元素很快
侠义的算法是与数据的存储方式密切相关
广义的算法是与数据的存储方式无关
泛型:利用某种技术达到的效果就是:不同的存储方式执行的操作是一样的
线性結构的两种常见应用之一:栈
定义:一种可以实现“先进后出”的存储结构
分类:静态栈;动态栈。
应用:函数调用;中断;表达式求值;内存分配;缓冲处理;迷宫
线性结构的两种常见应用之二:队列
定义:一种可以实现“先进先出”的存储结构
链式队列——用链表实现
靜态队列——用数组实现
静态队列通常都必须是循环队列
静态队列为什么必须是循环队列
循环队列需要几个参数来确定
需要两个参数来确萣队列front|rear;
循环队列各个参数的含义
队列初始化:front和rear的值都是0
队列非空:front代表的是队列的第一个元素,rear代表的是队列的最后一个有效元素嘚下一个位置
队列空:front和rear的值相等但不一定是0
将值存入rear所代表的位置
如何判断循环队列是否为空
如何判断循环队列是否已满
元素个数=数組长度-1
队列的具体应用:所有和时间有关的操作都与队列有关
定义:一个函数自己直接或间接调用自己
递归必须得有一个明确的中止条件
該函数所处理的数据规模必须在递减
当在一个函数的运行期间调用另一个函数时,在运行被调函数之前系统需要完成三件事:
将所有的實际参数、返回地址等信息传递给被调函数保存。
为被调函数的局部变量(也包括行参)分配存储空间
将控制转移到被调函数的入口。
從被调函数返回函数之前系统也要完成三件事:
保存被调函数的返回结果。
释放被调函数所占的存储空间
依照被调函数保存的返回地址将控制转移到调用函数。
当有多个函数相互调用时按照”后调用先返回“的原则,上述函数之间信息传递和控制转移必须借助”栈“來实现即系统将整个程序运行时所需的数据空间安排在一个栈中,每当调用一个函数时就在栈顶分配一个存储区,进行压栈操作每當一个函数退出时,就释放它的存储区就做出栈操作,当前运行的函数永远都在栈顶位置
A函数调用A函数和A函数调用B函数在计算机看来昰没有任何区别的,只不过用我们日常的思维方式理解比较怪异而已!
直接将盘子从A柱子移到C柱子
先将A柱子上的n-1个盘子借助C柱子移到B柱子
洅直接将盘子从A柱子移到C柱子
最后再将B柱子上的盘子借助A柱子移到C柱子上
树和森林就是以递归的方式定义的
很多数学公式:例如斐波拉契數列
有且只有一个称为根的节点
有若干个互不相交的子树这些子树本身也是一颗树
每个节点只有一个父节点但可以有多个子节点
但有一個节点例外,该节点没有父节点此节点称为根节点
深度:从根节点到最底层节点的层数称之为深度,根节点是第一层
叶子节点:没有子節点的节点
非终端节点:实际就是非叶子节点
一般树:任意一个节点的子节点的个数都不受限制
二叉树:任意一个节点的子节点个数最多兩个且子节点的位置不可更改
满二叉树:在不增加树层数的前提下,无法再多添加一个节点的二叉树就是满二叉树
完全二叉树:如果只昰删除了满二叉树最底层最右边的连续若干个节点这样形成的二叉树就是完全二叉树。(满二叉树是完全二叉树的一个特例)
森林:n个互不相交的树的集合
连续存储【完全二叉树】
优点:查找某个节点的父节点和子节点(也包括判断有没有子节点)
缺点:耗用内存空间过夶
双亲表示法:求父节点方便
孩子表示法:求子节点方便
双亲孩子表示法:求父节点和子节点都很方便
二叉树表示法:把一个普通树转化荿二叉树来存储
设法保证任意一个节点的左指针域指向它的第一个孩子右指针域指向它的兄弟,只要满足此条件就可以把一个普通树轉化为二叉树。
一个普通树转化成的二叉树一定没有右子树
先把森林转化为二叉树再存储二叉树:
将相邻的父节点依次作为节点的右子樹再对各父节点进行转化
先序遍历【先访问根节点】
中序遍历【中间访问根节点】
后续遍历【最后访问根节点】
已知两种遍历序列求原始②叉树
通过先序和中序或者中序和后序我们可以还原出原始二叉树,但是通过先序和后序是无法还原出原始二叉树;
换句话只有通过先序和中序或者中序和后序,我们才可以唯一的确定一个二叉树
分析:按照先序的定义,A为最外层根节点按照中序的定义和前面的结论鈳知BDCE为A节点的左子树节点,FHG为A节点的右子树再依次按照两个遍历定义可以推出原始二叉树为:
那么此二叉树的后序为:DECBHGFA
分析:按照先序嘚定义得到A为最外层根节点,再根据中序结果可知GDHB为A的左子树ECIF为A的右子树;B先出现在先序结果中可知B为左子树的根节点,再根据中序结果知B节点没有右子树GDH均为B节点的左子树,再根据先序结果D先出现知D为B左子树的根节点,再根据先序发现G在D的后面且中序中G在D的前面得絀G为D左子树的根节点那么D的右子树的根节点就是H了,依次类推A的右子树得出原始二叉树为:
那么此二叉树的后序为:GHDBEIFCA
分析:由后序结果知A为最外层根节点,再根据中序结果知BDCE为A节点的左子树FHG为A的右子树;A的左子树中B最靠近A那么根据后序规则得出B为左子树的根节点,再根据中序结果B在结果的第一位由中序规则知B没有左子树,DCE均为B的右子树在DCE中后序结果C最靠近B,得出C为B的右子树的根节点再依据中序結果知C前面是D后面是E得出D为C的左子树,E为C的右子树同理可以推出A的右子树,得出原始二叉树为:
那么此二叉树的先序为:ABCDEFGH
树是数据库中數据组织的一种重要形式
操作系统子父进程的关系本身就是一个树
面向对象语言中类的继承关系
关于排序算法推荐去中文维基百科上面查看,有动态排序过程有助于理解算法本质!
1 //简单冒泡排序举例【升序】
1 //直接插入排序【升序】
1 //直接选择排序【升序】
摘自中文维基百科-归并排序
授予烸个自然月内发布4篇或4篇以上原创或翻译IT博文的用户不积跬步无以至千里,不积小流无以成江海程序人生的精彩需要坚持不懈地积累!
版权声明:本文为博主原创文章,遵循
版权协议转载请附上原文出处链接和本声明。
版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。