二叉树
树形的最简单的模型,每个节点最多有两个子节点
一般来说,非二叉树,可以简化成二叉树
每个子节点有且仅有一个父节点,整棵树只有一个根节点
具有递归的结构特征,用递归的方法处理,可以简化算法
三种遍历序:
前序遍历 D-L-R
中序遍历 L-D-R
后序遍历 L-R-D
比如:1是根节点 2是左子节点 3是右子节点
前序遍历 1 2 3
中序遍历 2 1 3
后序遍历 2 3 1
二叉树的一般形式:
根节点、枝节点、叶节点
父节点和子节点
左子节点和右子节点
左子树和右子树
大小和高度(深度)
满二叉树和完全二叉树
满二叉树:
每层节点数均达到最大值
所有枝节点均有左右子树
完全二叉树:
前面n-1 层是满的,最后1层可以不满,
但是从左向右连续排列
平衡二叉树:
左右层数不能相差1的;
二叉树的编码实现:
顺序二叉树 -----数组只能还原完全二叉树,所以不是完全二叉树的 需要变成完全二叉树
最大的问题 就是如果二叉树离完全二叉树标准特别远,内存的浪费非常大。
因此二叉树虽然可以用 顺序结构实现,但更常见的用链表实现。
链式表二叉树
每个节点由 数据、左子节点和右子节点组成(二叉链表)。也可以加上父节点指针(三叉链表)。
二叉链表实现的二叉树 单向的; 三叉链表实现的是二叉树是 双向的。
struct BsTreeNode{
int data;//数据
struct BsTreeNode* left;//左子节点,也可以代表左边的子树
struct BsTreeNode* right;//右子节点,也可以代表右边的子树
};
编码实现 有序二叉树:
有序二叉树的原理:
首先有一个根节点(第一个节点),放入第二个节点的时候,和根节点比较,如果比根节点大,放
在根节点的右边,如果小则放在左边。(相等的话,看情况处理)。
左右子树亦分别为有序二叉树。
基于有序二叉树的排序和查找,可获得O(logN)级的平均时间复杂度
回顾:
二叉树,最简单的树型结构,每个父节点最多有两个子节点
二叉树具备递归的特征,所以编码时会大量使用递归。
二叉树有顺序结构和链式结构两种实现方式,顺序结构的实现方式必须存储完全二叉树,
不是完全二叉树的用空节点补成二叉树以后存储,因此内存上浪费比较大。
链式结构的二叉树分为二叉链表实现和三叉链表实现,三叉链表多了父节点的指针。
二叉树的遍历分为三种:前序、中序、后序
算法:
数据结构 存一起
算法 算一下
广义上说,算法就是解决问题的方法。(说到底是数学问题)
排序算法:----无序变成有序
冒泡、选择、插入、快速、归并
查找算法:----查找数据
线性查找(从头到尾查找)二分查找(有序,从中间开始查找)
冒泡排序:排序有升序和降序,升序就是从小到大,降序就是从大到小。
算法:
相邻的比较,如果前面比后面大,交换。从第一对比到最后一对,最大就在最后面。
依次对前面的元素进行相同的操作。n-1轮以后,排序成功。
假如有一轮 依次都没有交换的话,则说明有序了。
1. 相邻的预算两两比较,前者大于后者,彼此交换
2. 从第一对到最后一对,最大元素沉降到最后
3. 针对未排序部分,重复以上步骤,沉降次大值
4. 每次扫描越来越少的元素,直至不再发生交换
评价:
平均时间复杂度O(N的平方)
稳定排序
对数据的有序性非常敏感
冒泡排序效率总体来说是比较低的。平均时间复杂度O的平方,就是N的平方次。
但如果排序前就基本有序的话,则冒泡的效率就很高了。
1 #include <stdio.h>
2 #include <stdlib.h>
3 //数组做参数,必须指定数组长度,数组不能返回
4 void bubble_sort(int data[],size_t size){//冒泡排序
5 int i,j;
6 for(i=0;i<size-1;i++)//执行size-1轮
7 {
8 int flag=1;//记录是否发生过交换
9 for (j=0;j<size-1-i;j++)//j<size-1-i,多加-i可以提高效率
10 {
11 if (data[j] > data[j+1]){//前面的比后面大
12 int temp = data[j];//交换算法
13 data[j] = data[j+1];
14 data[j+1] = temp;
15 flag=0;//发生了交换
16 }
17 }
18 if (flag) break;//没有交换就退出
19 }
20 }
21 int main()
22 {
23 int a[]={4,3,2,1,5,7,6};
24 bubble_sort(a,7);
25 int i;
26 for(i=0;i<7;i++)
27 printf("%d\n",a[i]);
28 return 0;
29 }
插入排序 1-n
算法:
第一个元素必然有序,然后把第二个到第n个元素插入前面的有序序列中,保证每次插入以后依然有序。
如何保持插入后依然有序呢?
把插入的数据和前面的数据进行比较,如果插入数据比前面数据小的话,前面的数据后移一位,插入数据
继续向前比较,如果插入数据不比前面的数据小的话,把数据插入到前面的数据后面即可。如果已经比较
到最前面的数据话,插入数据依然最小,插入数据放在第一位即可。
1 首元素自然有序
2 取出下一个元素,对已排序序列,从后向前扫描
3 大于被取出元素者后移
4 小于等于被取出元素者,将被取出元素插入其后
5 重复步骤2,直至处理完所有元素
评价
平均时间复杂度O(N的平方)
稳定排序
对数据的有序性非常敏感
不交换只移动,优于冒泡排序
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 void insert_sort(int data[],size_t size){//插入排序
5 int i,j;
6 for(i=1;i<size;i++){//从下标1(第二个)开始插入排序
7 int inserted = data[i];//先取出插入数据避免覆盖
8 for(j=i;(j>0 && inserted < data[j-1]);j--){//从最后向前依次比较
9 data[j] = data[j-1];//后移动一位,不需要交换
10 }
11 data[j] = inserted;//j就是inserted应该插入的下标
12
13 }
14
15 }
16
17 int main()
18 {
19 int a[]={4,3,2,1,5,7,6};
20 insert_sort(a,7);
21 int i;
22 for(i=0;i<7;i++)
23 printf("%d\n",a[i]);
24 return 0;
25 }
选择排序:
求数组最小值的算法:
int arr[];
int min = arr[0];
for(i=0;i<length;i++){
if (arr[i] < min) min = arr[i];
}
选择排序的算法:
1 先从数组中找到最小的元素,和第一个元素交换
2 再从余下的元素中找到最小的元素和第二个元素交换
3 依次递推,直到从最后两个元素中找到最小的,和第n - 1个元素交换,排序完成。
特点:
时间复杂度也是O(N的平方)级
对数据的有序性不敏感,因为选择最小值时,无论最小值在哪里,都需要全部比较完。
选择排序比冒泡好,因为交换次数少。
注:
找最小元素时,需要存储的不是最小值而是最小值的下标,这样才能完成交换。
数组的操作就是下标的控制。
1 #include <stdio.h>
2 #include <stdlib.h>
3 void select_sort(int data[],size_t size){//选择排序
4 //思路:先从头开始记录最小值的下标,然后和i下标做数据交换
5 int i,j,min;
6 for (i=0;i<size-1;i++)
7 {
8 int index = i;//每次都从i开始比较
9 for (j=i+1;j<size-i;j++){//j从index+1位置开始比较
10 if (data[j] < data[index]) {
11 index = j;//最小值的当前下标
12 }
13 }
14 //插入
15 if (i!=index){
16 int temp = data[i];
17 data[i] = data[index];
18 data[index] = temp;
19 }
20 }
21 }
22 int main()
23 {
24 int data[]={4,3,5,1,7,6,8,2};
25 select_sort(data,7);
26 int i;
27 for(i=0;i<7;i++)
28 printf("%d\n",data[i]);
29 }
快速排序:----应用最广泛的排序
qsort
一个元素,如果它前面的所有元素都比它小,它后面的元素都比它大(也包含等于)
那么这个元素的位置就是排序以后它应该在的位置。比如3 2 1 4 5 7 8 9 6 ,其中5
算法:
1先取任意一个元素(做基准),然后通过算法(前小、后大)确定这个元素的位置。
2数组分成了3部分:基准之前,基准,基准之后,基准已经排好序了
3递归操作基准前的部分和基准后的部分,直到元素个数不超过1就自然有序了。
特点:
平均速度非常快,但不稳定。
确定基准位置的算法:
定义一个i从头开始,一个j从尾开始。然后从头找比基准大的,移动到当前基准的位置,
基准位置和i重合;然后在从j向前找比基准小的,移动到i的位置,基准位置和j重合,直到
i==j结束,并把基准数放回来即可。
1 从待排序序列中任意挑选一个元素,作为 基准
2 将所有小于基准的元素放在基准之前,大于基准的元素放在基准之后,等于基准
的元素放在基准之前或之后,这个过程称为分组。
3 以递归的方式,分别对基准之前和基准之后的分组 继续进行 分组,直到每个分组内
的元素个数不多于1个----自然有序---为止。
就地分组:
在不额外分配内存空间的前提下,实现以基准为中心的分组
评价:
平均时间复杂度O(NlogN)
非稳定排序
若每次都能均匀分组,则排序速度最快
1 #include <stdio.h>
2 #include <stdlib.h>
3 void quick_sort(int data[],size_t left,size_t right){//快速排序,全或部分
4 size_t p = (left+right)/2;//以中间做基准
5 int num = data[p];//把基准数取出来。
6 int i = left;
7 int j = right;
8 while(i<j){//没有碰面循环,i==j循环结束
9 //如果i==p或找到比基准大的,i不移动
10 for(;!(i>=p || num<data[i]);i++);//移动i,不做任何操作;
11 if(i<p){//找到比num大的数字了
12 data[p] = data[i];
13 p = i;//p和i重合,下一次循环i不动,也不赋值
14 }
15 for(;!(j<=p || num>data[j]);j--);
16 if (j>p)
17 {
18 data[p] = data[j];
19 p = j;
20 }
21 }
22 data[p] = num;//基准数放入应该在的位置,归位
23 if ((p - left) > 1) quick_sort(data,left,p-1);
24 if ((right - p) > 1) quick_sort(data,p+1,right);
25 }
26 int main()
27 {
28 int data[]={4,3,5,7,1,2,6};
29 quick_sort(data,0,6);
30 int i;
31 for (i=0;i<7;i++)
32 printf("%d\n",data[i]);
33 return 0;
34 }
查找算法 :
线性查找-----从头到尾找一遍,如果有,就退出循环,如果没有,循环结束就知道了。
二分查找-----必须是有序元素才能使用二分查找。
从中间点开始查找,如果大于 去后半部分,如果小于 去前半部分。
每次查找都是从中间点开始。
1 #include <stdio.h>
2 #include <stdlib.h>
3 //返回find的下标,如果找不到返回-1;
4 int line_find(int data[],size_t size,int find){
5 int i;
6 for (i=0;i<size;i++)
7 {
8 if (data[i] == find) return i;//找到了
9 }
10 return -1;//没找到
11 }
12 int half_find(int data[],size_t size,int find){
13
14 int left = 0;//二分的左下标
15 int right = size -1; //二分的右下标
16 while (left <= right)//二分查找的算法
17 {
18 int mid = (left+right)/2;//二分的中间点
19 if (find < data[mid]) right = mid - 1;
20 else if (find>data[mid]) left = mid + 1;
21 else return mid;
22 }
23 return -1;
24 }
25 int main()
26 {
27 int data[]={7,2,4,5,1,3,6};
28 int in = line_find(data,7,2);
29 printf("in = %d\n",in);
30 int in1 = line_find(data,7,20);
31 printf("in1 = %d\n",in1);
32 int data2[]={1,2,3,4,5,6,7,8};
33 int in2 = half_find(data2,7,2);
34 printf("in2 = %d\n",in2);
35 int in3 = half_find(data2,7,20);
36 printf("in3 = %d\n",in3);
37
38 }
39
常用算法笔记
最新推荐文章于 2023-11-06 20:34:46 发布