1.排序-冒泡算法
讲算法太空洞,直接上实例:
上实例中,当后面的都已经排序好的时候其实是不需要交换的,所以就会终止循环。
利用递归的方式写冒泡排序:
2. 归并排序
归并排序是把待排序序列分为若干个子序列,每个子序 列是有序的。然后再把有序子序列合并为整体有序序列。先把待排序列分为两部分,然后各部分再分为两部分,一直分下去,直到不能再分为 止,然后在两两合并两个有序数组,直到合并完为止。
3.插入排序
插入排序的原理是默认前面的元素都是已经排序好的,然后从后面逐个读取插入到前面 排序好的合适的位置,就相当于打扑克的时候每获取一张牌的时候就插入到合适的位置 一样。插入排序可以分为两种,一种是直接插入还一种是二分法插入,直接插入的原理 比较简单,就是往前逐个查找直到找到合适的位置然后插入。
二分法插入排序:
4.基数排序
基数排序是非比较排序算法,算法的时间复杂度是O(n)。 基数排序的主要思路是,将所有待比较数值(注意,必须是正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始, 依次进行一次稳定排序,这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。
#include <iostream> using namespace std; /********************************************************* Function:rxsort Description:基数排序 Input: 数组A[l,h]; 数组中最大元素的位数d,例如最大数为999,则d为3; 进制数k,如果是10进制数,k为10; Output:排序好的数组; Others:对数字1234来说,预定第0位为4,第1位为3,依次类推; *********************************************************/ bool rxsort(int A[],int l,int h,int d,int k){ if(NULL==A||l>h) return false; int size = h-l+1; int* counts = new int[k];//用于计数排序的辅助数据,详见计数排序 int* temp = new int[size];//用于存储重新排序的数组 int index; int pval=1; //依次处理不同的位 for(int i=0;i<d;i++){ //counts数组清零 for(int j=0;j<k;j++) counts[j] = 0; for(int j=l;j<=h;j++){ /* 1.data[j]/pval:去掉数字data[j]的后i个数,例如: 当data[j]=1234,i=2时,此时pval=100,data[j]/pval=12; 2.(data[j]/pval)%k:取数字data[j]/pval的最后一位数 3.(int)(data[j]/pval)%k:取数字data[j]的第i位数 */ index = (int)(A[j]/pval)%k; /* 统计数组A中每个数字的第i位数中各个数字的频数,用于计数排序; */ counts[index]++; } //计算累加频数,用户计数排序 for(int j=1;j<k;j++) counts[j] = counts[j] + counts[j-1]; //使用倒数第i+1位数对A进行排序 for(int j=h;j>=l;j--){ index = (int)(A[j]/pval)%k; temp[counts[index]-1] = A[j]; counts[index]--; } //将按第i为数排序后的结果保存回数组A中 for(int j=0;j<size;j++) A[j+l] = temp[j]; //更新pval pval = pval*k; } delete[] counts; delete[] temp; } int main(){ int A[] = {712,303,4,18,89,999,70,26}; rxsort(A,0,7,3,10); for(int i=0;i<8;i++) cout<<A[i]<<" "; }
5.快速排序
快速排序原理是首先要找到一个中枢,把小于中枢的值放到他前面,大于中枢的值放到 他的右边,然后再以此方法对这两部分数据分别进行快速排序。
6.选择排序
选择排序和冒泡排序有一点点像,选择排序是默认前面都是已经排序好的,然后从后面 选择最小的放在前面排序好的的后面,首先第一轮循环的时候默认的排序好的为空,然 后从后面选择最小的放到数组的第一个位置,第二轮循环的时候默认第一个元素是已经 排序好的,然后从剩下的找出最小的放到数组的第二个位置,第三轮循环的时候默认前 两个都是已经排序好的,然后再从剩下的选择一个最小的放到数组的第三个位置,以此类推。
7.堆排序
堆排序,也可以理解为二叉树排序,这里的堆分为两种,一种是大 顶堆,一种是小顶堆,我们所有的排序方法都以升序为主,其实倒序原理也都差不多
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; void adjust(int arr[], int len, int index) { int left = 2*index + 1; int right = 2*index + 2; int maxIdx = index; if(left<len && arr[left] > arr[maxIdx]) maxIdx = left; if(right<len && arr[right] > arr[maxIdx]) maxIdx = right; // maxIdx是3个数中最大数的下标 if(maxIdx != index) // 如果maxIdx的值有更新 { swap(arr[maxIdx], arr[index]); adjust(arr, len, maxIdx); // 递归调整其他不满足堆性质的部分 } } void heapSort(int arr[], int size) { for(int i=size/2 - 1; i >= 0; i--) // 对每一个非叶结点进行堆调整(从最后一个非叶结点开始) { adjust(arr, size, i); } for(int i = size - 1; i >= 1; i--) { swap(arr[0], arr[i]); // 将当前最大的放置到数组末尾 adjust(arr, i, 0); // 将未完成排序的部分继续进行堆排序 } } int main() { int array[8] = {8, 1, 14, 3, 21, 5, 7, 10}; heapSort(array, 8); for(auto it: array) { cout<<it<<endl; } return 0; }
8.shell(希尔)排序
shell排序在不相邻的元素之间比较和交换。利用了插入排序的最佳时间代价特性,它试图将待排序序列变成基本有序的,然后再用插入排序来完成排序工作。在执行每一次循环时,Shell排序把序列分为互不相连的子序列,并使各个子序列中的元素在整个数组中的间距相同,每个子序列用插入排序进行排序。
#include<iostream> using namespace std; const int INCRGAP = 2; void shellSort(int a[],int len) { int insertNum = 0; unsigned gap = len/INCRGAP; // 步长初始化 while(gap) // while gap>=1 { for (unsigned i = gap; i < len; ++i) // 分组,在每个子序列中进行插入排序 { insertNum = a[i];//将当前的元素值先存起来方便后面插入 unsigned j = i; while (j >= gap && insertNum < a[j-gap])//寻找插入位置 { a[j] = a[j - gap]; j -= gap; } a[j] = insertNum; } gap = gap/INCRGAP; } } int main() { int array[11] = {2, 1, 4, 3, 11, 6, 5, 7, 8, 10, 15}; shellSort(array, 11); for(auto it: array) { cout<<it<<endl; } return 0; }
排序法 | 平均时间 | 最差情形 | 稳定度 | 额外空间 | 备注 |
冒泡 | O(n^2) | O(n^2) | 稳定 | O(1) | n小时较好 |
选择 | O(n^2) | O(n^2) | 不稳定 | O(1) | n小时较好 |
插入 | O(n^2) | O(n^2) | 稳定 | O(1) | 大部分已排序时较好 |
基数 | O(logRB) | O(logRB) | 稳定 | O(n) |
B是真数(0-9), R是基数(个十百) |
Shell | O(nlogn) | O(ns) 1<s<2 | 不稳定 | O(1) | s是所选分组 |
快速 | O(nlogn) | O(n^2) | 不稳定 | O(nlogn) | n大时较好 |
归并 | O(nlogn) | O(nlogn) | 稳定 | O(1) | n大时较好 |
堆 | O(nlogn) | O(nlogn) | 不稳定 | O(1) | n大时较好 |