封装链表:
1、单链表
由于不封装链表结构时,链表的尾添加效率低
其次非法位置的判断效率也很低,只能通过遍历来判断
节点:
数据域
指针域next
链表结构:
头指针
尾指针
节点数量
注意:单链表的删除节点,无论是按位置、按值删除,都需要找到待删除节点的前一个节点
2、静态链表
节点:
数据域
游标
特点:
1、静态链表的节点存储在一段连续的内存中,通过游标来访问下一个节点
2、插入、删除节点时,只需要修改游标的值即可,不需要动态申请、释放节点,因此得名静态链表
3、但是也牺牲了随机访问的功能、对内存的要求高,只是给没有指针的编程语言提供实现链表的方式
3、循环链表
链表的最后一个节点的next不指向NULL,而是指向第一个节点,这种链表称为循环链表,如果是单链表则称为单循环链表,好处是可以在任意一个节点开始遍历整个链表
4、双向链表
注意:双向链表一般会实现为双向循环链表,最后一个节点的next指向第一个节点,第一个节点的prev指向最后一个节点
节点:
前趋指针 prev
数据域 data
后继指针 next
封装双循环链表结构:
头节点指针 head
节点数量
注意:封装的是带头节点的双链表,不然的话插入、删除操作可能会改变head的指向,处理起来就需要分情况其麻烦,因此带头节点不需要考虑以上情况
注意:
1、删除操作时,不再需要找待删除节点的前一个位置
2、因为是双向循环链表,所以可以根据需要从前往后遍历,也可以从后往前遍历,从而提高查找的效率
5、Linux内核链表
既然节点中不能包含万物,那么就让万物来包含节点
6、通用链表
能够存储任意类型的数据到链表中,并提供对应的操作
万能指针 void*
C语言中任意类型的指针可以转换成void*类型
void*类型指针可以转换成任意类型指针
节点:
void* ptr; // 数据域
指针域;
链表结构:
头指针
数量
核心点:
1、void* 确保能存储任意类型数据
2、普通操作可参考双链表即可
2、通过回调模式来实现一些特殊操作,例如:遍历、按值操作、排序
数组与矩阵:
数组:存储空间连续的表结构
矩阵:带有二维信息的数据,一般使用二维数组来存储矩阵
矩阵中存储数据的元素个数一般都少于所申请的内存个数,如果直接以二维数组存储会浪费内存,因此可以通过压缩矩阵成一维数组的方式来节约内存
特殊矩阵:行数、列数 n 行号i 列号j
上三角矩阵:
[0][1][3][6]
[ ][2][4][7]
[ ][ ][5][8]
[ ][ ][ ][9]
压缩方法:使用一维数组压缩
一维数组长度:(n+1)*n/2
下标的对应关系:(j+1)*j/2+i == 一维数组下标
要求:j >= i时 才有有效数据,才进行压缩
下三角矩阵:
[0][ ][ ][ ]
[1][2][ ][ ]
[3][4][5][ ]
[6][7][8][9]
压缩方法:使用一维数组压缩
一维数组长度:(n+1)*n/2
下标的对应关系:(i+1)*i/2+j == 一维数组下标
要求:j <= i时 才有有效数据,才进行压缩
对称矩阵:沿左上-右下对角线对称
[0][1][3][6]
[1][2][4][7]
[3][4][5][8]
[6][7][8][9]
参考上三角\下三角进行压缩
对角矩阵:沿左上-右下对角线两边有数据
[0][1][ ][ ]
[2][3][4][ ]
[ ][5][6][7]
[ ][ ][8][9]
压缩方法:使用一维数组压缩
一维数组长度:3n-2
下标的对应关系:2*i+j
要求:abs(i-j)<=1时 才有有效数据,才进行压缩
稀疏矩阵:有效数据不多且位置无规律,绝大多数位置都是无效数据不需要表示使用的,但是数量没有具体标准,全凭感觉
压缩方式:使用三元组来进行压缩
三元组:有三个数据项:
行、列、值
构成一个整体,该整体既可以顺序存储也可以链式存储
优点:节约存储空间
缺点:矩阵是具备随机访问的功能,但是压缩成三元组后失去了随机访问的效果,只能遍历查找某行某列的数据
树型结构:
1、树的基本概念:
一种表示层次关系(一对多)的数据结构
有且仅有一个特定的节点,该节点没有前趋节点,称为这棵树的根节点
剩余有n个(n>=0)有限个的节点组成互不相交的子集,每个子集也都可以是一棵树,都被称为根节点是子树
注意:树中有树,树型结构具有递归性
2、树的表示方式:
倒悬树、凹凸法、嵌套法
3、树的相关专业术语(不同资料不同说法):
节点(结点):组成树的基础元素,同时它也可以是一棵树
节点的度:该节点子树(直接相关的子节点)的数量
树的度(密度):树中所有节点的数量
树的层次:从根节点算第1层,依次往下递增
节点的层次:从该节点起算第1层,依次往下递增
树的深度:树的最大层次数
叶子节点:节点的度为0的节点
双亲节点和孩子节点(父节点、子节点):
节点的直接节点称为该节点的子节点,该节点就是它们子节点的父节点
兄弟节点:具有同一个父节点的节点,互为兄弟节点
堂兄弟节点:双亲在同一层时节点互为堂兄弟节点
祖先节点:从该节点出发,该节点是经过的所有节点的祖先节点
森林:由n个不相交的树组成的集合称为森林
4、树的存储方式
树可以顺序存储、链式存储、还可以混合存储,以存储的信息为依据,有以下不同的存储表示方式:
双亲表示法:顺序
位置(下标) data 双亲位置
0 A -1
1 B 0
2 C 0
3 D 0
4 E 1
5 F 1
6 G 2
7 H 3
8 I 3
9 J 4
10 K 6
优点:查找双亲很方便
缺点:查找孩子效率较低
孩子表示法:
顺序存储:
位置(下标) data sub_arr(存储子节点下标的数组)
0 A 1、2、3
1 B 4、5
2 C 6
3 D 7、8
4 E 9
5 F
6 G 10
7 H
8 I
9 J
10 K
缺点:非常浪费空间
链式+顺序:
位置(下标) data ListHead(指向第一个子节点链表)
0 A 1->2->3->N
1 B 4->5->N
2 C 6->N
3 D 7->8->N
4 E 9->N
5 F
6 G 10->N
7 H
8 I
9 J
10 K
优点:节省空间
优点:查找孩子方便
缺点:查找双亲不方便
兄弟表示法:
双亲只存储第一个子节点,然后链式指向所有的兄弟节点
数据项:
第一个孩子 数据 指向兄弟的指针
优点:方便地查找兄弟节点,找孩子节点也方便
缺点:不方便找双亲