常用算法笔记

		
二叉树 
	树形的最简单的模型,每个节点最多有两个子节点
	一般来说,非二叉树,可以简化成二叉树
	每个子节点有且仅有一个父节点,整棵树只有一个根节点
	
	具有递归的结构特征,用递归的方法处理,可以简化算法
	
	三种遍历序:
		前序遍历 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 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值