十大排序算法代码总览(C++)
2018-03-30 17:14
169 查看
注:
算法稳定性
定义:待排序序列中的相同关键字记录经过排序后相对次序保持不变。比如Xm=xn,原本Xm在Xn之前,排序后依然Xm在Xn之前。
条件:算法的稳定性由具体算法决定,且在一定条件下算法稳定性也会发生转变。
稳定性意义:只有在排序一个复杂对象的多个数字属性且初始顺序存在意义时,才需要注意算法的稳定性,即需要尽量保持原有排序序列的意义。比如原本商品按价格高低排序,想着想要按销量排序,且使得同销量的商品依然保持价格高低的排序,这是可以使用稳定性算法。
1冒泡排序(Bubble Sort)
简述:重复进行相邻数组元素的两两比较,并按规则进行交换,直到没有元素再需要交换。最终使得大的元素逐渐沉到数列底部,相较小的元素浮现到数列前端。
算法描述:
1 比较相邻两个元素,如果第一个比第二个大,就交换位置。
2 从第一对开始,对数组中的每一对相邻的两个元素重复步骤1,使得最大的元素沉到数组底部。
3 重复步骤2,除了底部已经排序好的元素。(每一趟都会多一个以排序好的元素)
4 重复以上步骤直到排序完成。
算法分析:
最好:T(n)=O(n);数据全部正序
最差:T(n)=O(n^2);数据全部反序
平均:T(n)=O(n^2);
代码实现
#include<iostream> using namespace std; void swap(int &a, int &b) {//交换函数 int tmp = a; a = b; b = tmp; } void bubbleSort(int a[],int len) { for (int i = 0; i < len; ++i) {//排列len趟完成排序 for (int j = 0; j < len - i - 1; ++j) {//每趟排序的元素都从第一个元素开始到尾部没有排序好的元素。第一趟为第一个元素到最后一个元素,排出了最大元素。第二趟为第一个元素到倒数第二个元素(排除以排序好的元素),排出第二大的元素。 if (a[j] > a[j + 1]) { swap(a[j], a[j + 1]); } } } } int main() { int a[] = { 520,0,1,9,56,100,1,85,5,3,6 }; int len = sizeof(a) / sizeof(a[0]); bubbleSort(a, len); for (int i = 0; i < len; ++i) { cout << " " << a[i]; } getchar(); return 0; } //运行结果: 0 1 1 3 5 6 9 56 85 100 520
算法改进
1**增加了反向冒泡。传统冒泡排序每一趟排序一次,找出一个最大值。改进后每一趟排序两次,正向冒泡,找出最大的元素;反向冒泡,找出最小元素,使得一次可以得到两个最终值。从而减少排序趟数。**
2**增加了标志点flag**。目的在于记录每一趟最后一次交换的元素位置,即表示标志点之后或者之前的位置已经排好,后续无需再排,缩小排序区间,减少排序次数。
#include<iostream> using namespace std; void swap(int &a, int &b) { int tmp = a; a = b; b = tmp; } void bubbleSort(int a[],int len) { int low = 0, high = len - 1; while (low < high) {//排序趟数。排序区间[low,high]。 int flag = 0;//标志点 for (int i = low; i < high; ++i) {//第一次正向冒泡 if (a[i] > a[i + 1]) { swap(a[i], a[i + 1]); flag = i; } } high = flag;//表示标志点之后的元素已经排好,区间右值缩小。 for (int i = high; i > low; --i) {//第2次反向冒泡 if (a[i] < a[i - 1]) { swap(a[i], a[i - 1]); flag = i; } } low = flag;//表示断点之前的元素已经排好,区间左值缩小。 } } int main() { int a[] = { 520,0,1,9,56,100,1,85,5,3,6 }; int len = sizeof(a) / sizeof(a[0]); bubbleSort(a, len); for (int i = 0; i < len; ++i) { cout << " " << a[i]; } getchar(); return 0; } //运行结果: 0 1 1 3 5 6 9 56 85 100 520
2选择排序(Select Sort)
简述将数组分为已排序和待排序两个区间,即有序区和无序区。每次从无序区中选出最小/最大的元素与无序区的第一个元素(即有序区尾部)交换位置,直到无序区只剩一个元素,排序完成。
算法描述
1 将数组划分为有序区和无序区。(开始有序区为空,无序区[0,n-1])
2 在无序区中找出最大的那个元素,与该区间第一个元素交换。(有序区元素个数加1,无序区减1)
3 重复步骤2 n-1次,排序完成。(排序趟数为n-1,最后一个元素无需排序)
算法分析
时间复杂度最稳定,无论什么时候都为:T(n)=0(n^2)
代码实例
#include<iostream> using namespace std; void swap(int &a, int &b) { int tmp = a; a = b; b = tmp; } void selectSort(int a[], int len) { for (int i = 0; i < len - 1; ++i) { int minIndex = i; for (int j = i; j < len; ++j) {//找出无序区最小元素的下标 if (a[j] < a[minIndex]) { minIndex = j; } } swap(a[i], a[minIndex]);//无序区第一个元素与最小值交换。 } } int main() { int a[] = { 5,89,562,4,2,0,56512,4512,5 }; int len = sizeof(a) / sizeof(a[0]); selectSort(a, len); for (int i = 0; i < len; ++i) { cout << " " << a[i]; } getchar(); return 0; } //运行结果: 0 2 4 5 5 89 562 4512 56512
3插入排序(Insert Sort)
简述插入排序跟选择排序很像,都分为有序区和无序区。但是选择排序是每次都从无序区中选出最小元素插入到有序区末尾,而插入排序是直接将数组的第一个元素作为有序区的第一个元素,每次都拿出无序区第个一元素插入到有序区合适的位置上,直到无序区为空,排序完成。
算法描述
1 将数组分为有序区和无序区,有序区0,无序区[1,n-1];
2 取下无序区第一个元素,保存其值。
3有序区中元素从后往前与新元素比较,如果新元素更小,旧元素往后移。
3 重复步骤3,直到新元素大于或等于旧元素,将新元素插入该元素之后。
4 重复步骤234, n-1次,排序完成。
算法分析
最好:T(n)=o(n),数组元素正序排列
最坏:T(n)=o(n^2)数组元素反序排列
平均:T(n)=o(n^2)
代码实例
#include<iostream> using namespace std; void sertSort(int a[], int len) { for (int i = 1; i < len; ++i) { int key = a[i];//保存无序区第一个元素为key int j = i - 1; while (!(j <0) && a[j] > key) {//新元素在有序区寻找位置 a[j + 1] = a[j]; j--; } a[j+1] = key; } } int main() { int a[] = {5,45,1,3,0,99,2,10 }; int len = sizeof(a) / sizeof(a[0]); sertSort(a, len); for (int i = 0; i < len; ++i) { cout << " " << a[i]; } getchar(); return 0; } //运行结果: 0 1 2 3 5 10 45 99
算法改进
新元素在插入到有序区时,使用二分法查找位置而非一个一个依次查找。
#include<iostream> using namespace std; void sertSort(int a[], int len) { for (int i = 1; i < len; ++i) { int key = a[i]; int left = 0, right = i-1; while (!(left > right)) {//在区间内查找位置 int middle = (left + right) / 2; if (a[middle] > key) right = middle-1; else left = middle+1; } for (int j = i - 1; !(j<left); --j) { a[j+1] = a[j ]; } a[left] = key;//left为新元素要插入的位置。 } } int main() { int a[] = {5,45,1,3,0,99,2,10 }; int len = sizeof(a) / sizeof(a[0]); sertSort(a, len); for (int i = 0; i < len; ++i) { cout << " " << a[i]; } getchar(); return 0; } //运行结果: 0 1 2 3 5 10 45 99
4希尔排序(Shell Sort)
简述希尔排序是以某个增量h为步长跳跃分组进行插入排序,由于增量是一个从h逐渐缩小至1的过程,所以又称缩小增量排序。
其核心在于间隔序列设定,即增量的设定,这也是也插入排序的本质区别。插入排序始终增量为1。
最佳增量:k趟排序增量步长为(2^k)-1,即增量序列(2^k)-1,…15,7,3,1
算法描述
1确定增量序列(t1,t2…tk)ti>tj,tk=1;
2按增量序列个数k分成k趟排序
3每趟排序按对应增量ti,将序列分割成若干子序列,分别进行直接插入排序。
简述2
希尔排序实际上是将一维数组分成具有不同列数的二维数组(对应方式,a[i]->a[i/h][i%h])。在每一趟排序中对每一列进行插入排序。列宽也就是增量,增量减小也就是列数减小。
以排序数组a[]={10,8,4,3,1,5,7,9,2,6},增量分别为5,2,1为例:
代码实例
#include<iostream> using namespace std; void swap(int&a, int&b) { int tmp = a; a = b; b = tmp; } void shellSort(int a[], int len) { int gap = len ; while (gap = gap / 2) {//增量 cout << "每列待排序元素:"<<endl; for (int i = gap; i < len; i++) { cout << i << " "; int key = a[i];//待排序元素 int j = i - gap; for (; j+1>0&&a[j ] > key; j -= gap) {//插入排序 a[j + gap] = a[j]; } a[j + gap] = key; }cout << endl; cout << "增量" << gap << "的排序结果:" << endl; for (int i = 0; i < len; ++i) { cout << " " << a[i]; }cout <<endl; } } int main() { int a[] = { 10,8,4,3,1,5,7,9,2,6}; int len = sizeof(a) / sizeof(a[0]); shellSort(a, len); cout << "排序最终结果:"; for (int i = 0; i < len; ++i) { cout << " " << a[i]; } getchar(); return 0; }
5归并排序(Merge Sort)
简述采用递归和分治的思想,首先将数组二分成多个子序列,然后两两子序列进行比较与合并,使其合并为一个完全有序的序列。不断进行比较与合并,使子序列们最终合并为一个完整有序的序列。
算法描述
1将数组二分为多个子序列
2子序列进行排序(注:只有1个元素的序列本身就已经是排序好的序列)
3排序好的子序列间进行比较与合并。
3子序列完全合并为一个有序序列
算法分析
最佳:o(n)
最坏:o(nlogn)
平均:o(nlogn)
#include<iostream> using namespace std; void merge(int a1[], int na1, int a2[], int na2) { int tmp[1000]; int t = 0, i = 0< 10568 /span>, j = 0,k=0; while( i < na1&&j < na2){ if (a1[i] > a2[j]) { tmp[t++] = a2[j++]; } else tmp[t++] = a1[i++]; } while (i < na1) { tmp[t++] = a1[i++]; } while (j < na2) { tmp[t++] = a2[j++]; } while(k<t){ a1[k] = tmp[k++]; } } void mergeSort(int a[],int len) { if (len>1) { int mid = len / 2; int *a1 = a; int na1 = mid; int *a2 = a + mid ; int na2 = len - mid; mergeSort(a1, na1); mergeSort(a2, na2); merge(a1, na1, a2, na2); } } int main() { int a[] = {0,7,5,2,1,3,8,4,6,9 }; int len = sizeof(a) / sizeof(a[0]); mergeSort(a,len); for (int i = 0; i < len; ++i) { cout << " " << a[i]; } getchar(); return 0; }
6快速排序(Quick Sort)
简述分治和递归的应用。选取数组中一个元素为基准(pivot)P,对数组进行排序,使得比P大的元素都在P的右边,比P小的元素在P的左边。然后对以P为分界点的左右子串递归进行快排。
算法描述
1从数列中选取一个元素作为基准;
2进行分区操作(partition)。重新排列数列,使得比基准小的元素都在其左边,比基准小的元素都在它右边,即分为左子列,基准,右子列。
3对左右子列递归进行快排。
算法分析
最好:o(nlogn)
最坏:o(n^2)
平均:o(nlogn)
代码范例1
#include<iostream> using namespace std; void swap(int &a, int &b) { int tmp = a; a = b; b = tmp; } void quickSort(int a[], int low, int high) { if (low < high) { int i = low - 1; int j = low; int key = a[high];//基准 for (int j = low; j <= high; ++j) {//使比基准小或等于基准的元素前移。 if (a[j] <=key) { ++i; swap(a[i], a[j]); } } quickSort(a, low, i - 1); quickSort(a, i + 1, high); } } int main() { int a[] = { 0,4,1,2,3,0,0,0 }; int len = sizeof(a) / sizeof(a[0]); quickSort(a, 0, len - 1); for (int i = 0; i < len; ++i) { cout << " " << a[i]; } getchar(); return 0; }
代码范例2
#include<iostream> using namespace std; void quickSort(int a[], int low, int high) { if (low >= high) return; int i, j, key; i = low; j = high; key = a[low]; while (i < j) { while (i<j&&a[j]>=key) { j--; } a[i] = a[j]; while (i < j&&a[i] <=key) { i++; } a[j] = a[i]; } a[i] = key;//基准到位 quickSort(a, low, i - 1); quickSort(a, i + 1, high); } int main() { int a[] = { 0,4,1,2,3,0,0,0 }; int len = sizeof(a) / sizeof(a[0]); quickSort(a, 0, len - 1); for (int i = 0; i < len; ++i) { cout << " " << a[i]; } getchar(); return 0; }
7堆排序(Heap Sort)
简述堆排序是将数组构建成大顶堆,即根节点是数组中最大元素,将根节点与堆底最后一个元素交换,使得最大值排到末尾,即已排序好。将剩下的n-1个元素重新调整为大顶堆,在堆顶/根节点处得到第二大的值,与堆底最后一个元素交换,便又排序好一个元素。
算法描述
1将数组构建成大顶堆
2交换堆顶元素和堆底元素
3调整堆,使其重新成为大顶堆
4重复步骤2和步骤3 n-1次,排序完成。n为数组长度。
算法分析
最好、最坏,平均都为o(nlogn)
代码示例
#include<iostream> using namespace std; void swap(int &a, int &b) { int tmp = a; a = b; b = tmp; } void heap(int a[],int node,int len) { int nodecopy = a[node]; for (int i = 2 * node + 1; i < len; i = 2 * i + 1) {//遍历node所有下属节点 if(i + 1 < len&&a[i + 1] > a[i])//如果右子树节点存在且右子树节点大于左子树,那么将下标移到右子树位置 i++; if (a[i] > a[node]) { a[node] = a[i]; node = i; } } a[node] = nodecopy;//确定a[node]最终位置 } void heapSort(int a[],int len) { for (int node = len / 2 - 1; node >= 0; --node) { heap(a, node, len); } for (int i = len-1;i>0; --i) { swap(a[0], a[i]); heap(a, 0, i); } } int main() { int a[] = { 7,0,1,2,8,5,9, }; int len = sizeof(a) / sizeof(a[0]); heapSort(a, len); for (int i = 0; i < len; ++i) { cout << " " << a[i]; } getchar(); }
8计数排序(Count Sort)
简述非比较排序。计数排序是利用哈希原理,记录元素出现的频次。在统计结束后可以直接遍历哈希表,将数据填回数据空间。由于是空间换时间,所以适合对数据范围集中的数据使用。而且由于用数组下标表示,只适合只有正整数,0的数据。
算法描述
1统计数组中元素出现的频次并找出极值。
2填充原数组。
算法分析
T(n)=O(n+k)
注:k为范围,即新开辟的数组大小
代码示例
#include<iostream> using namespace std; void countSort(int a[], int len) { int low = a[0], high = a[0]; for (int i = 0; i < len; ++i) {//找范围 low = a[i] < low ? a[i] : low; high = a[i] > high ? a[i] : high; } int range = high - low+1; int *count = new int[range]; memset(count, 0, sizeof(int)*(range)); for(int i=0;i<len;++i){//统计频次 count[a[i]-low]++; } for (int i = 0,j=0; i < range; ++i) {//赋值 while (count[i]--) { a[j++] = i+low; } } } int main() { int a[] = { 2, 2, 3, 8, 7,0,4}; int len = sizeof(a) / sizeof(a[0]); countSort(a, len); for (int i = 0; i < len; ++i) { cout << " " << a[i]; } getchar(); return 0; }
9基数排序(Radix Sort)
简述非选择排序。将元素依次按低位到高位进行分类排序(个位,十位,百位…)与收集。即分别排序,分别收集。
注:适用范围,最好小于1000;数字为0或正整数。
算法描述
1取得数组中最大位数。
2从低位开始,对数组进行排序。
3将排序好的元素复制到原始数组。
4重复2、3步骤到最高位。排序完成。
算法分析
最好、最差、平均均为O(n*k)注:k为位数。
代码范例
#include<iostream> #include<vector> using namespace std; int getnum(int a[], int len) { int max = a[0]; int num = 1; for (int i = 1; i < len; ++i) { max=a[i] > max ? a[i] : max; } while (max /= 10) { num++; } return num; } void radixSort(int a[], int len) { int num = getnum(a, len);//获得位数 vector<vector<int>>radix(10); for(int k=0;k<num;++k){ for (int i = 0; i < len; ++i) {//存放元素 int t = int(a[i] / pow(10, k))%10; radix[t].push_back(a[i]); } vector<vector<int> >::iterator p; vector<int>::iterator q; int i = 0; for (p = radix.begin(); p != radix.end(); ++p) {//取出元素 for (q = (*p).begin(); q !=(*p).end(); ++q) { a[i++] = *q; } } for (int i = 0; i < 10; ++i) {//清空容器中元素 if(!radix[i].empty()) radix[i].clear(); } } } int main() { int a[] = { 0,1,89,4,45,41,7,9,0,52,80,100 }; int len = sizeof(a) / sizeof(a[0]); radixSort(a, len); for (int i = 0; i < len; ++i) { cout << " " << a[i]; } getchar(); return 0; }
10桶排序(Bucket sort)
简述顾名思义,桶排序就是把同类元素放在相同的桶里,然后又对桶内元素递归调用桶排序本身,是分治和递归的典型。
计数排序,基数排序以及桶排序的比较:
三者都出现了桶的概念。
计数排序是一个桶只存单一值,
基数排序是根据元素的位数来往桶里存放数据,
而桶排序是存储一定范围的数据。
算法描述
1确定桶的数量和桶区间
2遍历列表把元素放到对应桶里
3重复步骤2,即对桶中元素递归调用桶排序。
4把排序好的元素放回原列表,直到排序完成
算法分析
平均:T(n)=o(n^2)
#include<iostream> #include<vector> using namespace std; int getRange(vector<int> a, int begin, int end,int &min,int &max) {//获得数组元素范围和极值 for (int i = begin + 1; i <= end; ++i) { min = a[i] < min ? a[i] : min; max = a[i] > max ? a[i] : max; } return max - min+1; } void bucketSort(vector<int>&a, int begin, int end) {//容器做参数时用引用传递来调换元素顺序, if (end - begin <1) return;//递归出口 int min, max;min=max = a[0]; int range = getRange(a, begin, end, min, max); //获得元素范围和极值 int bucketNum = 5;//本次定义了5个桶 int gap = range / 5+1;//设定桶区间 vector <vector<int > > bucket(bucketNum);//用二维容器来装桶 for (int i = begin; i <= end; ++i){ cout << "桶编号: " << (a[i] - min) / gap << "放入元素:" << a[i] << endl; bucket[(a[i]-min )/ gap] .push_back( a[i]);//元素放在不同的桶里 } for (int i = 0; i < bucketNum; ++i) { bucketSort( bucket[i],0,bucket[i].size()-1);//对桶里的元素递归调用桶排序 } for (int i = 0,j=0; i < bucketNum; ++i) { if (!bucket[i].empty()) {//桶非空判断 for (vector<int>::iterator p = bucket[i].begin(); p!=bucket[i].end(); ++p) {//桶里排序好的元素放回原容器a a[j++] = *p; } } } cout << endl; } int main() { vector<int>a; for (int i = 0,j=100; i<20; ++i) { a.push_back(j--); } bucketSort(a, 0, a.size()-1); cout << "排序结果:" << endl; for (int i = 0; i<a.size(); ++i) { cout << " "<<a[i]; } return 0; }
相关文章推荐
- 十大排序算法 JAVA代码
- 十大经典排序算法(含JAVA代码实现)
- 十大经典排序算法最强总结(含Java代码实现)
- 几大典型排序算法的c++代码实现及总结
- C++排序算法代码汇总
- 各种排序算法的c++代码实现
- 【归纳整理】十大经典排序算法的简单C++实现
- 机器学习十大算法总览(含Python3.X和R语言代码)
- 排序算法 C++代码实现
- [置顶] 机器学习十大算法总览(含Python3.X和R语言代码)
- 各种排序算法代码C++版
- C/C++ 排序算法大全代码
- 十大经典排序算法最强总结(含JAVA代码实现)
- 先码后看 十大经典排序算法最强总结(含Java代码实现) 侵立删
- c++代码实现各种排序算法
- 基本排序算法的实现代码(c++)
- c++几种排序算法代码
- 十大排序算法 JAVA代码
- C++实现顺序排序算法简单示例代码
- 十大经典排序算法皇冠体育足球竞猜源码下载最强总结(含JAVA代码实现)