数据结构是什么
数据:现实生活中一切可以处理的信息
结构:逻辑结构、存储结构
研究的是数据的逻辑结构,存储结构及其操作。
逻辑结构
事物与事物之间在现实生活中的抽象的一种逻辑关系
存储结构
顺序存储:在逻辑上相邻的元素,在物理空间上也相邻
优点:查找方便,
存储空间的利用率可以达到
1
缺点:插入和删除不方便,
申请空间的时候,必须是一片连续的空间,对空间的要求比较高
会用空间碎片的产生
链式存储:在逻辑上相邻的元素,在物理空间上不一定相邻
优点:插入元素不需要移动大量的空间
对空间的要求没那么大,
缺点:查找不方便
存储空间的利用率不足
1
,没有顺序存储的大
索引存储:依据索引表查找数据大概位置,详细查找数据本身(冲突没有解决号的哈希存储)
优点:查找方便
缺点:有索引表的存在,要浪费空间
插入元素,删除元素之后,索引表要更新
哈希存储:根据关键字直接就能定位到记录本身,就能拿到数据
优点:查找方便,插入,删除也方便
缺点:如果哈希函数设计的不合理,查找的效率就会很低
操作
增、删、改、查、创、销
逻辑结构
----
确定研究对象,把对象的关系抽象出逻辑结构
|
|
把数据存到计算机里面
存储结构
----
顺序存储、链式存储、索引存储、哈辛存储
|
|
目的是为了程序能运算
操作
----
研究怎么运算,算法
|
|
用某一个语言实现该算法的功能
程序
线性结构
线性结构的顺序存储
顺序表:
学生管理系统:
typedef struct student
{
char name[20];
char id[20];
char add[20];
}data_type;
图书馆的书籍管理系统
typedef struct book
{
char name[20];
char id[20];
char add[20];
}data_type;
特点:
1.逻辑上相邻的元素,在物理空间上也相邻===》空间连续
2.大小固定
3.表满不能存,表空不能取
特点1和特点2
#define SIZE (10)
typedef struct list
{
data_type data[SIZE]; //struct student arr[];//存储空间
int count; //用来指示当前存储多少元素了
}List;
typedef struct list
{
data_type (*data)[]; //指向数组的指针 数组:顺序表的存储空间
int size; //当前顺序表有多大的空间
int count; //用来指示当前存储了多少元素 表满:count == size
}List;
顺序表的创建
![](https://i-blog.csdnimg.cn/blog_migrate/8510417bbdac59073feb6cdf490cba79.png)
插入元素
删除元素
显示元素
销毁
释放空间
导入步骤
顺序表的扩容
线性结构的链式存储
链表的分类:
按方向分:单链表、双链表
按是否循环分:循环链表,不循环链表
按是否带头节点:带头结点的链表,不带头结点的链表
带头结点的不循环单链表
认识链表
结点定义
创建链表
插入结点
显示链表
给链表删除元素
销毁单链表
按找头删、尾删的原则,把所有的数据节点全部删除(
free
)
当只剩下头节点的时候再释放头节点
逆置一个单链表
栈
对原来的单链表采用头删,对新链表采用头插
循环单链表
在循环链表下:尾结点的Next指向头节点
双链表
带头结点的不循环双链表
双链表表结点的定义
双链表的创建
双链表的插入元素
头插、尾插、中间插入
双链表的删除元素
双链表的显示
线性表,链表,顺序表之间的区别?
线性表是一种逻辑结构
顺序表和链表是线性表在顺序存储下和链式存储下的体现
链表和顺序表的区别:
1.
链表是链式存储,顺序表是顺序存储
2.
顺序表会有空间碎片产生,链表没有空间碎片产生
3.
链表一般多用于插入、删除较多的场景
顺序表一般用于查找较多的场景
4.
顺序表的存储空间利用率比链表的大
链表和顺序表怎么选择?
1.
从空间来说
顺序表对空间的要求比链表大
顺序表的利用率比链表大
2.
从操作来说
多用于查找,用顺序表
多用于插入、删除,用链表
3.
从编译环境来说
不支持指针类型操作的编译器不能使用链表
双端队列
栈的应用
编译器不支持使用指针类型操作,场景又是多插入、删除操作
使用静态链表,本质是二维数组
![](https://i-blog.csdnimg.cn/blog_migrate/3b952f47bfccc396d2725abd9ad11c0f.png)
受限的线性表
栈:受限在了操作上
只允许数据在一段进行插入和删除操作,允许操作的一段叫做栈顶
特点:先进后出(
FILO
)
队列:受限在了操作上
只允许在一段执行插入操作,另一端执行删除操作,允许插入的一段叫做队尾,允许删除操作的一段叫做队头
特点:先进先出(
FIFO
)
串:受限在了存储上
只允许存储字符
* ' a — 1
栈
顺序存储
和顺序表相同
栈的定义:
//1.
存储空间连续
//2.
大小固定
//3.
表满不能存,表空不能取
//4.
只允许在一段(栈顶)进行插入删除操作
入栈和出栈
打印栈
//函数功能:显示栈
//函数参数:需要显示的栈
//函数返回值:成功返回OK,失败返回失败原因
int ShowItem(Stack *pStack)
{
//入参判断
//能否打印
//从i=0打印到i=top-1
return OK;
}
链式存储
线性表的链式存储是一样的
头是栈顶:头插、头删
尾是栈顶:尾插、尾删
操作的时候一般选择头作为操作
共享栈:
队列
顺序存储
队列的定义
//定义大小
#define SIZE (10)
//定义数据类型
typedef int data_type;
//栈的定义
typedef struct stack
{
data_type data[SIZE]; //存储空间
//只能在栈顶进行操作
int top; //指示栈顶
}Stack;
//队列的定义
typedef struct queue
{
data_type data[SIZE]; //存储空间
//在队尾插入、队头删除
int tail; //指示队尾
int head; //指示队头
}Queue;
队列的创建
队列入队出队
循环队列
链式存储
对链表限制住了插入和删除的位置
双端队列![](https://i-blog.csdnimg.cn/blog_migrate/b601c819a4359db95a73af4446b15340.png)
栈的应用![](https://i-blog.csdnimg.cn/blog_migrate/d35dbbc6e6d30eef62c121d928e774d4.png)
树形结构
二叉树
满二叉树:有
k
层,恰好有
2
k
-1
个结点
完全二叉树:在满二叉树的基础上,从右往左,从下往上依次去除结点
一颗普通的树转成二叉树:
树形结构的顺序存储
树形结构的链式存储
树的结点的定义
树的结点的创建
树的结点的插入
树的节点的遍历
先序遍历:
中序遍历:
后序遍历:
![](https://i-blog.csdnimg.cn/blog_migrate/f4134b6e2db9d37c1ddd560e3907cafa.png)
递归形式的遍历,非递归的写法
用栈
深度优先
广度优先
层次遍历
队列
![](https://i-blog.csdnimg.cn/blog_migrate/a37a5a8e3a926871568978cac8822067.png)
树的结点的删除
待删除结点没有孩子,直接删除
待删除结点有一个孩子,子承父位
待删除结点有两个孩子,找右子树中最小的值或者左子树中最大的值来继承
平衡二叉树
每一个结点的左子树的层数和右子树的层数不超过
2
目的:解决树的降维问题(把树将成链表),提高效率
线索二叉树
网状结构
分类:
按有无方向可以分为:有向图、无向图
按是否带权值:带权图和不带权图
网状结构的顺序存储
网状结构的链式存储
算法
算法是有限指令的有序集合。
算法是有穷的,程序是无穷的
程序
=
算法
+
数据结构
算法的特征
有穷性:算法必须在有限个语句能描述完
确定性(无二义性):每一条语句只能有一个解释
可行性:能运行的
输入:
输出:
怎么样评判算法的好坏:
常见的查找算法
顺序查找:遍历
折半查找:二分查找
限制:必须有序、必须是一个顺序表
分块查找:块间有序,块内无序
内部排序
插入:
直接插入:重新构建一个链表
折半插入:和二分查找类似
希尔排序:增量,逐渐减少的,直到增量为
1
为止
交换:
冒泡:每一次运行总会将最小的或者最大的放到前面,如果需要交换,一直在交换
快速排序
*
:
![](https://i-blog.csdnimg.cn/blog_migrate/80c82834d53844a9b3671497f6c4b9b1.png)
选择:
简单选择:每一次运行总会将最小的或者最大的放到前面,最后只交换一次
堆(大根堆,小根堆):根
>=
左右孩子的,牵扯到树的变化,所以只有特定场景下才使用
多路归并:
![](https://i-blog.csdnimg.cn/blog_migrate/994add080f2b72f3bc9355faa65a68d7.png)
基数排序:
外部排序
基于多路归并的外部排序:
![](https://i-blog.csdnimg.cn/blog_migrate/40b13ab2a2646641938f1bf34392cee5.png)