数据结构
一、基本知识-概述
1、数据结构的概述:
-
定义:我们如何把现实中大量而复杂的问题,以特定数据类型和特定的存储结构保存到主存储器(内存)中,以及在此基础上为实现某个功能(比如查找某个元素,删除某个元素,对所有元素进行排序)而执行的相应的操作,这个相应的操作也叫做算法。
数据结构 = 个体 + 个体的关系
算法 = 对存储数据的操作 -
算法:解题的方法和步骤
衡量算法的标椎:
1.时间复杂度:大概程序要执行的次数,而非执行时间
2.空间复杂度:算法执行过程中大概所占用的最大内存
3.难易程度
4.健壮性
程序 = 数据的存储 + 数据的操作 + 可以被计算机执行的语言
2、预备知识
指针:
地址:
结构体: 动态内存的分配和释放,
什么叫结构体:结构体是用户根据实际需要自己定义的符合数据类型
注:结构体变量不能加减乘除,但可以相互赋值。普通结构体变量和结构体指针变量作为函数传参的问题。
3、数据结构
-
模块一:线性结构
连续存储【数组】 数组:元素类型相同,大小相等 离散存储【链表】
线性结构的两种常见应用之一:【栈】
线性结构的两种常见应用之二:【队列】 -
模块二:非线性结构
【树】
【图】 -
模块三:查找和排序
【折半查找】
【排序】
二、线性数据结构
1、数组
2、链表
- 定义:
n个节点离散分配,彼此通过指针相连,每个节点只有一个前驱节点,每个节点只有一个后继节点,首节点没有前驱节点,尾结点没有后继节点。 - 分类:
单链表
双链表:每个节点有两个指针域
循环链表:能通过任何一个节点找到其他所有的节点,即最后一个节点又指向首节点
非循环链表 - 算法:
遍历
查找
清空
销毁
求长度
排序
删除节点:需要释放删除的节点free()
插入节点
算法:
狭义的算法是与数据的存储方式密切相关
广义的算法是与数据的存储方式无关
泛型:利用某种技术达到的效果就是:不同的存储方式,执行的操作是一样的
- 链表的优缺点
学算法,做算法题的步骤:
1、自己先想
2、想不出来,看懂别人的程序:
流程、每个语句的功能、试数
3、自己去敲,多次去敲,改错
3.栈
动态分 配的内存-堆
静态分配的内存-栈
- 分类:
静态栈:内核数组
动态栈:内核链表 - 算法:
压栈
出栈【弹栈】 - 应用:
函数调用
中 断
表达式求值
内存分配
缓冲处理
迷宫
- 栈需要的两个参数:
top:指向栈顶,控制出和进
bottom:指向栈底
栈底的地址高,栈顶的地址低,从高地址–>低地址
4.队列
-
定义:
一种可以实现“先进先出”的存储结构
两个参数:
front:指向队列的头,控制数据的入
rear: 指向队列的尾,控制数据的出
-
分类:
链式队列 - 用链表实现
静态队列 - 用数组实现
静态队列通常都必须是循环队列
静态队列:
1.静态队列为什么必须是循环队列
2.循环队列需要几个参数来确定
两个参数:
front、rear
3.循环队列各个参数的含义
2个参数不同场合有不同的含义:
1).队列初始化
front和rear的值都是0
2).队列非空
front代表队列的第一个元素
rear代表队列的最后一个有效元素的下一个元素
3).队列为空
front和rear的值相等,但不一定为0
4.循环队列入队、出队位算法
入队两步完成:
1).将值存入r所代表的位置
2).r = (r+1) % 数组的长度
出队:
f = (f+1) % 数组的长度
5.如何判断循环队列是否为空
如果front与rear的值相等,则该队列一定为空
6.如何判断循环队列是否已满
front的值可能比rear大,也可能比rear小
当然二者也可能相等
两种方式:
1).多增加一个标识参数
2).少用一个数组元素
如果r和f的值紧挨着,则表明队列已满
语法:
if( (r+1) % 数组的长度 = f )
已满
else
不满
- 队列算法:
入队:
出队:- 队列的具体应用:
所有和时间有关的操作都与队列有关
- 队列的具体应用:
5.递归
递归要满足的三个条件:
1.递归必须有得一个明确的中止条件
2.该函数所处理的数据规模必须在递减
3.这个转化是可解的
循环和递归
递归:
易于理解、速度慢、存储空间大
循环:
不易理解、速度快、存储空间小
例子:
1.求阶乘
2.1+2+3…100的和
3.汉诺塔
4.走迷宫
递归的应用:
树和森林就是以递归的方式定义的
树和图的很多算法都是以递归的方式定义的
三、非线性数据结构
1.树
大话数据结构
-
树定义:
专业定义:
1.有且只有一个称为根的节点
2.有若干个互不相交的子树,这些子树本身也是一棵树
通俗的定义:
1.树是由节点和边组成的
2.每个节点只有一个父节点,但可以有多个子节点
3.但有一个节点例外,该节点没有腹肌诶单,此节点称为根节点 -
专业术语:
节点 父节点 子节点
子孙 堂兄弟
深度:
从根节点到最底层节点的层数称之为深度
根节点是第一层
叶子节点:
没有子节点的节点,其实也叫终端节点
非终端节点:
实际就是非叶子节点
度:
自己诶但的个数称为度,如:一个节点有3个孩子(3个节点),这个节点的度就是3 -
树分类:
- 一般树:
任意一个节点的子节点的个数都不受限制 - 二叉树:
任意一个节点的子节点个数最多有两个,且子节点的位置不可更改- 分类:
-** 一般二叉树
** 满二叉树:在不增加树的层数的前提下,无法再多添加一个接地那的树就是满二叉树
** 完全二叉树:如果只是删除了满二叉树最底层最右边的连续若干个节点,这样形成的二叉树就是完全二叉树。
- 分类:
- 森林
n个互不相交的树的集合
- 一般树:
-
树的存储
- 二叉树的存储
连续存储【完全二叉树】
优点:查找某个节点的父节点和子节点(也包括判断有没有子节点)很快
缺点:耗用内存空间大
链式存储 - 一般树的存储
双亲表示法:求父节点方便
孩子表示法:求子节点方便
双亲孩子表示法:求子节点和父节点都很方便
- 二叉树的存储
-
二叉树表示法
把一个普通树转化成二叉树来存储
具体转换方法:
设法保证任意一个节点的
左指针域指向它的第一个孩子
有指针域指向它的下一个兄弟
只要能满足此条件,就可以把一个普通树转化为二叉树
一个普通树转换成的二叉树,一定没有右子树,即根节点只有左子树,没有右子树,因为它的有边的节点必须为根节点的兄弟,根无兄弟 -
二叉树的操作
遍历:
先序遍历 :根 - 左 - 右
中序遍历 :左 - 根 - 右
后序遍历 :左 - 右 - 根
先后序遍历左子树
再后序遍历右子树
再访问根节点
已知两种遍历序列求原始二叉树:
通过先序和中序 或者 中序和后序,我们可以还原出原始的二叉树,但是通过先序和后序是无法还原出原始的二叉树的。 -
树的应用
树是数据库中数据组织的一种重要形式
操作系统子父进程关系本身就是一棵树
面向对象中语言种类的继承关系
四、排序
1.排序的种类
冒泡
插入
选择
快速排序
归并排序
数据结构研究的是数据的存储和数据的操作的一门学问
数据的存储分为两部分:
个体的存储
个体关系的存储
从某个角度而言,数据的存储最核心的就是个体关系的存储,个体的存储可以忽略不计