C语言与数据结构小总结,自我总结+各处收集来的他人的总结(很多记不清了,若有侵权请联系我删!
一、常用C语言小总结
1)数据类型、运算符与表达式
逗号运算符优先级最低,左操作数为先运算,但这是为右操作数服务,因为整个式子的结果为右操作数的运算结果。
2)输入输出与数组
当遇到需要输入保存空格的情况,使用gets或fgets(还会在最后存多一个\n),而不能使用scanf(遇到空格自动结束输入)。
fgets(a,b,c)a为变量,可为指针;b为其可使用的空间大小;c为stdin(固搭)
eg:scanf(“%s %c”,&a,&b);这里的%c前要空一个格,不然在输完%s后分隔两个数据时就会把那个空格放入b中了。
3)指针
1、必须掌握动态内存申请内存malloc(x)【x代表多少字节】,即申请堆空间。指向堆空间的指针使用完后需要释放,继而置NULL。
2、堆、栈差异:
(1)栈空间的系统自动分配的,已知大小的,效率高;而堆空间是自己申请的,空间可动态,效率比栈低。
(2)栈空间在函数使用完后就会释放,而堆空间会一直保存着,除非free。
3、指针的表示方法:p、p[]
4)结构体
1、结构体的大小不是将所有数据的类型大小的总和,而是在每种数据对齐4位后才计算。
2、 结构体指针的定义 eg:struct student *p; struct student *p,q;(定义两个指针时不能忽略 * 号)
结构体指针获取成员 eg: p->num或(p).num(不能写p.Num,因为 . 运算的优先级比高)
二、数据结构
1、typedef的使用:给数据类型起别名。
目的:为了代码规范,实现代码即含义。
Eg:
typedef struct student
{
Int n;
Int m;
}stu,*pstu
Typedef int INTEGER;
2、C++的引用
把&写进函数形参位置。
Eg:void x(int &a){} 此时操作a与操作实参一样。
3、逻辑结构与存储结构
逻辑结构 数据元素之间的逻辑关系
分类:集合(无序)、线性(一对一)、树形(一对多)、图形(多对多)
存储结构 数据结构在计算机上的实现
分类:顺序存储、链式存储、(索引存储、散列存储)
顺序存储与链式存储对比
4、时间复杂度与空间复杂度
时间复杂度:要忽略高阶项系数和低阶项。
eg:执行次数为3n3+2n时,时间复杂度为O(n3)
二分查找法,时间复杂度为O(log2n)
---------------------------------------------------------------------------------分割线
1、线性表
1)基本概念
定义:由n个相同类型的数据元素组成有序的集合。
线性表的长度:元素的个数
空表:元素为0个
前驱:an-1为an的前驱
后继:…
2)特点:元素有限、类型相同(即占用空间大小相等)、顺序性
小区分:
线性表为一种逻辑结构,而顺序表、链表是存储结构,两者为两种概念。
数据项构成数据元素,数据元素与数据项不是同一个概念。
3)优缺点
4)编程实现线性表的 增 删 改 查
2、单链表
1)头插和尾插
2)查找、删除
3、栈
编程实现过程:
1)定义结构体(数组data+,变量top)
2)初始化栈函数(top置-1,否则返回false)
3)确认是否初始化成功,成功后再继续
4)入栈函数(传入指针&S和数据x,若MaxSize-1==top即栈满,则返回false;否则data[++S.top]=x)
5)获取栈顶元素(传入指针S和数据&x<以获取弹出的值>,若栈为空,则false;否则x=data[S.top])
6)出栈函数(传入指针&S和数据&x<以获取弹出的值>,若栈为空,则false;否则x=data[S.top–]<给完值再移回上一位置>)
4、循环队列(为存储结构)
1)定义结构体(数组data,变量front,变量end)
2)初始化函数(传入指针Q,设置front=end=0,返回true)
3)判断是否为空队列(传入指针Q,若end%MaxSize=front,则true;否则false)
4)入队函数(传入指针&Q,数据&x;若队列满<(end+1)%MaxSize=front>,则false;否则Q.data[end++]=x 放入数据并返回显示)
5)出队函数(传入指针&Q,数据&x;若队列空<end%MaxSize=front>,则false;否则x=Q.data[front++] 数据出队并返回显示)
5、队列的链式存储
1)定义结构体1(变量data,指针next)
定义结构体2(指针front,指针end)
2)初始化函数(传入指针&Q,malloc分配空间给Q.front和Q.end并指向同一个地方,Q.end->next置NULL,头节点的next置NULL)
3)入队函数:尾插法(传入指针&Q,数据x,分配空间指向p,front->next=p,p->data=x)
4)出队函数:尾部删除法(传入指针&Q,数据&x,x=Q.front->data,p=Q.front->next,Q.front->next=p.next)
6、层次建立二叉树
1)定义结构体1(链式存储,变量data、指针*left_child,right_child)
定义结构体2(链式队列,记录插入到哪个节点,指针front,*end,*now)
2)建树根(创建结构体变量,并置NULL)
3)添加
判断now.left是否为空,空则将申请的点地址放入,并将该点加入队列end;
判断now.right是否为空,空则将申请的点地址放入,并将该点加入队列end,还要将队列now指向下一个节点;
4)删除(使用遍历的方式)
5)查找(使用遍历的方式)
学习申请空间新函数:(int)calloc(1,sizeof(int))会自动将其空间都置0,申请的空间大小为 1sizeof(int)。*
7、遍历二叉树
(一)遍历
1)前序:深度优先遍历(因为一直在往下找左孩子,相当于一直深入下去)
父亲->左儿子->右儿子(按照顺序写好3个点后,再逐个插入他们的儿子)
2)中序:左儿子->父亲->右儿子(相当于将二叉树压扁,从左往右写过来)
3)后序:左儿子->右儿子->父亲
4)层次遍历(广度优先)
从上到下,从左到右的顺序逐层排下去。
8、线索二叉树
(埋个坑)
9、二叉查找树
(埋个坑)
10、哈希查找(散列)
概念:散列函数——通过某个输入(如字符串、数字)可以计算出一个对应的地址
记作:Hash(key)=Addr
实际使用注意:算出的下标要取余。
散列冲突——输入不同key但算出相同数值;
解决方法:使用链表存放在其后;
散列表——根据关键字能直接访问的数据结构(key与数据对应的表)
11、串
1)KMP算法
next数组求解方法:
(1)给模式串标号(从1开始或者从0开始)
(2)第一个置0,其后=最左边与最右边匹配的字符数+1
2)KMP改进算法:求Nextval数组
参考这里:1)三分钟搞定 数据结构 串 KMP算法next数组求值 考试抱佛脚系列_哔哩哔哩_bilibili
https://www.bilibili.com/video/BV1NJ411k7qw/?share_source=copy_web&vd_source=7d735355dd162d59dcebb187b0d9a720
2)四分钟搞定!数据结构 KMP改进算法 nextval数组求值_哔哩哔哩_bilibili
https://www.bilibili.com/video/BV1uJ411s7br/?share_source=copy_web&vd_source=7d735355dd162d59dcebb187b0d9a720
12、图
1)图的分类:有向图、无向图
2)图的表示方法:点+边
有向图:<v1,v2> v1为弧头(箭头直接指着的为头,而不是平常箭头的起始点),v2为弧尾;
无向图:<v1,v2> 此时v1与v2顺序可随意写。
3)存储结构:邻接矩阵、邻接表
(1)邻接表
下图为有向图与无向图存储方式(将每个点的与其相连的点用链表连接起来)
(2)邻接矩阵(使用二维数组将有点与之相连的位置置1,表示有连接;若是无向图则是关于斜对线对称矩阵),缺点是浪费空间。
4)遍历方式
(1)深度优先
(2)广度优先
(埋个坑)
.
.
.
5)最短路径算法
6)拓扑排序
拓扑排序:有向无环图才有,每次选入度为0的节点
逆拓扑排序:每次选出度为0的节点。(使用邻接矩阵存储时求解更快)
7)关键路径
【-------------------------------------------分割线-------------------------------------------】
13、排序算法(重要)
以下实现算法的存储结构都为顺序存储,即数组。
1)冒泡排序
从头到尾两两比较,找到大的就互换-------形成一趟循环找到一个最大的数。
2)快速排序
哨兵法:设第一个元素为标杆,其后的元素小的放其左边,大的放其右边,以此不断划分,然后可使用递归划分到只剩下一个元素【即最小的划分】从而实现排序。
挖坑法:在第0号元素处先作为坑,设置low、high代表数据最左、最右,low不断往后找,当low指向的元素比priot(先存着最右边的数据)的小时,把他插入high指向的位置,low结束后high不断往前找,直到找到比priot小的,把其填入low位置,由此不断循环找,直到low和high相等时排序结束。)
3)插入排序
哨兵法:0号元素作为暂存数据的地方,从2号元素开始,其后的元素不断向前找直到找到比它小的元素就插入它后面的位置,其他元素整体往后移。
另一种不使用哨兵的写法:
4)折半插入排序
(埋坑)
5)希尔排序
6)堆排序(重点)
用数组表示二叉树的层次建树的结构。不断把最大的放在根节点,父亲要比孩子大,找到最大的就把其与最后一个节点交换;下一次从除了最后那些节点开始重新找最大。
7)归并排序
把两个或多个有序的子序列合并为一个。
(1)分类
2路归并——二合一
k路归并——k合一
(2)算法过程:
①若low<high,则将序列分从中间mid=(low+high)/2分开
②对左半部分[low, mid]递归地进行归并排序
③对右半部分[mid+1, high]递归地进行归并排序
④将左右两个有序子序列Merge为一个
(3)具有稳定性
8)基数排序
(1)算法思想:
①将整个关键字拆分为d 位(或组);
②按照各个关键字位权重递增的次序(如:个、十、百),做d趟“分配"和"收集”,若当前处理的关键字位可能取得┌个值,则需要建 r 个队列;
③“分配":顺序扫描各个元素,根据当前处理的关键字位,将元素插入相应队列,一趟分配耗时O(n);
④"收集”:把各个队列中的结点依次出队并链接。一趟收集耗O(n)。
(2)擅长领域
①数据元素的关键字可以方便地拆分为d组,且d较小。
eg:给6个人的身份证号排序
②每组关键字的取值范围不大,即r较小。
③数据元素个n较大。
eg:1亿个数据