算法
- 数据结构中的算法,指的是数据结构所具备的功能
- 解决特定问题的方法,他是前辈们的优秀经验总结。
分治
- 把一个大而复杂的问题,分解为很多个小的而简单的问题,利用计算机的强大计算能力来解决问题。
- 实现的方法
- 循环、递归
-
递归:函数自己调用自己的一种行为,可以形成循环调用,进而实现分治算法
-
使用递归的情况:
- 问题过于复杂,无法拆解为循环
- 问题是非线性的,函数的每一次调用都会重新将数据压入栈空间,数据会保留。因此可以实现非线性的问题.在单线程模式下只能同时执行一个函数,当函数自己调用自己时(子级),会先执行子级,完事后返回上级继续执行
-
如何安全的实现递归
- 使用递归非常有可能造成"死循环",非常浪费资源。
- 先设置一个出口
- if(…) return …;
- 解决一个小问题
- 剩下的问题交给下一级
-
- 优点
- 代码简单、容易理解
- 缺点
- 比较耗费内存,且浪费时间
- 循环、递归
查找
- 顺序查找
- 从头到尾逐一比较 对数据没有要求,方法简单,效率低
- 二分查找
- 数据有序,从数据的中间位置开始查,
- 块查找、权重查找
- 适用于特殊条件下,需要对数据排序、分析、总结、归纳。
排序
- 稳定性:表中有相同的值时,算法会交换位置吗。
-
冒泡:
- 稳定排序 可以在排序时检测到数据是否已经有序,可以立即停止。如果无序的数据基本有序,则冒泡的效率很高
- 例
void bubble(int* arr,size_t len) { for(int i=len-1;i>0;i--) { bool flag = true; for(int j=0;j<i;j++) { if(arr[j] > arr[j+1]) { swap(arr[j],arr[j+1]); flag = false; } if(flag) break; } } }
-
插入排序:
- 当一列数已经有序,再有新加入的数时,时候使用插入排序
- 例
void cr(int* arr,size_t len) { for(int i=1; i<len; i++) { int a = arr[i],k = i; for(int j=i-1;j>=0 && arr[j] > a;j--) { arr[j+1] = arr[j]; k = j; } arr[k] = a; } }
-
选择排序:
- 先记录当前下标,对比完后下标内容互换。这是冒泡排序的一种变种,但没有冒泡对数据的敏感。排序时少了许多数据交换(数据比较混乱时比冒泡快)
- 例
void select_sort(int* arr,size_t len) { for(int i=0;i<len-1;i++) { int index = i; for(int j=i+1;j<len;j++) { if(arr[j] < arr[index]) index = j; } if(index != i) { swap(arr[index],arr[i]); } } }
-
快速排序:
- 一种基于交换的排序
- 例
void _quick(int* arr,size_t l,size_t r) { if(l >= r) return; //计算标杆下标 int pi = (l + r)/2; //备份标杆值 int pv = arr[pi]; //备份左右下标 int left = l,right = r; //不超出范围 while(left < right) {//在标杆左边寻找比标杆大的数 while(arr[left] <= pv && l < pi) left++; if(left<pi) {//与标杆交换位置,并记录新的标杆位置 arr[pi] = arr[left]; pi = left; } //在标杆右边寻找比标杆大的数; while(pi < right && arr[right] >= pv) right--; if(pi < right) { arr[pi] = arr[right]; pi = right; } } //还原标杆值 arr[pi] = pv; if(pi-l>1) _quick(arr,l,pi-1); if(r-pi>1) _quick(arr,pi+1,r); } void quick(int* arr,size_t len) { _quick(arr,0,len-1); }
-
堆排序:
- 先把待排序的数组当做完全二叉树,然后保障根结点最大,然后把根结点与最后一个元素交换,再调整二叉树,使根保持最大并且重复操作逐渐减少数组
- 例
void creat_heap(int* arr,size_t len,size_t root) { if(root >= len) return; int left = root*2+1; int right = root*2+2; creat_heap(arr,len,left); creat_heap(arr,len,right); int max = root; if(left < len) { if(arr[left] > arr[max]) max = left; } if(right < len) { if(arr[right] > arr[max]) max = right; } if(max != root) { swap(arr[max],arr[root]); } } void heap(int* arr,size_t len) { for(int i=0;i<len;i++) { creat_heap(arr,len,0); } }
-
归并排序:
- 不交换顺序,但需要借助额外的空间,用作临时存储空间
- 例
//递归方法 void _mergr(int* arr,size_t left,size_t right,int* temp) { if(left >= right) return; int pi = (left+right)/2; _mergr(arr,left,pi,temp); _mergr(arr,pi+1,right,temp); merge(arr,left,pi,right,temp); } void mergr(int* arr,size_t len) { int temp[10]; _mergr(arr,0,len-1,temp); } //循环方法 void merge(int* arr,size_t left,size_t pi,size_t right,int* temp) { int i = left,j = pi+1,k = left; while(i<=pi && j<=right) { if(arr[i] < arr[j]) temp[k++] = arr[i++]; else temp[k++] = arr[j++]; } while(i<=pi) temp[k++] = arr[i++]; while(j<=right) temp[k++] = arr[j++]; for(int a=left;a<=right;a++) { arr[a] = temp[a]; } }