十大排序算法(原理及代码实现细节)
Posted mch5201314
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了十大排序算法(原理及代码实现细节)相关的知识,希望对你有一定的参考价值。
本文参考一些书籍啊哈算法,数据结构与算法(清华大学),已经一些网上的博客
然后动图也是从网上偷来的(^_^),代码实现我尽量用大家容易懂的方式实现
数组居多,然后,桶排序(是别人代码,不过写的不完全正确后面会更新),都是学习嘛
有误的地方,还望各位指正,希望对你有帮助(其实很灵活的,在运用上),也不要这样就满足了
多多地运用,会使理解更深的。
按上面的顺序来吧
原理在代码里直接上动图吧
冒泡排序动图演示
冒泡排序代码实现
1 #include<iostream> 2 #include<cstdio> 3 #include<string.h> 4 using namespace std; 5 const int N = 1e5 + 10; 6 int a[N]; 7 //1.比较相邻的元素。如果第一个比第二个大,就交换它们两个; 8 //当然如果你是降序那就,第一个比第二个小,就交换它们两个; 9 //2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对, 10 //这样在最后的元素应该会是最大的数; 11 //3.针对所有的元素重复以上的步骤,除了最后一个; 12 //重复步骤1~3,直到排序完成。 13 void Bubble_sort(int* arr, int len) 14 { 15 for(int i = 1;i < len;i++) 16 for(int j = 1;j <= len - i;j++) 17 if (arr[j] > arr[j + 1])//升序 18 { 19 int tem = arr[j]; 20 arr[j] = arr[j + 1]; 21 arr[j + 1] = tem; 22 } 23 } 24 25 int main() 26 { 27 int n; 28 while (cin >> n) 29 { 30 for (int i = 1; i <= n; i++) 31 cin >> a[i]; 32 Bubble_sort(a, n); 33 cout << "After Bubble_sort: "; 34 for (int i = 1; i <= n; i++) 35 cout << a[i] << " "[i == n]; 36 } 37 return 0; 38 }
快速排序动图演示
快速排序代码实现
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 const int N = 1e5 + 10; 5 int a[N]; 6 7 //它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分, 8 //其中一部分的所有数据都比另外一部分的所有数据都要小, 9 //然后再按此方法对这两部分数据分别进行快速排序 10 //整个排序过程可以递归进行,以此达到整个数据变成有序序列 11 12 void quick_sort(int L, int R, int* arr) 13 { 14 if (L >= R) return; 15 int MostL = arr[L]; 16 int i = L, j = R; 17 while (i != j) 18 { 19 //先从最右边找出小于第一个元素的位置 20 while (arr[j] >= MostL && i < j) 21 --j; 22 23 //然后从最左侧找出大于第一个元素的位置 24 while (arr[i] <= MostL && i < j) 25 ++i; 26 27 //如果两个哨兵没有相遇交换二者 28 if (i < j) 29 { 30 int tem = arr[i]; 31 arr[i] = arr[j]; 32 arr[j] = tem; 33 } 34 } 35 36 //将第一个元素放在它应该在的位置 37 arr[L] = arr[i]; 38 arr[i] = MostL; 39 40 //对于当前哨兵位置的两侧还未有序,递归调用即可 41 quick_sort(L, i - 1, arr); 42 quick_sort(i + 1, R, arr); 43 } 44 45 int main() 46 { 47 int n; 48 while (cin >> n) 49 { 50 for (int i = 1; i <= n; i++) 51 cin >> a[i]; 52 53 quick_sort(1, n, a); 54 puts("After quick_sort:"); 55 for (int i = 1; i <= n; i++) 56 cout << a[i] << " "[i == n]; 57 } 58 return 0; 59 }
插入排序动图演示
插入排序代码实现
1 //插入排序的工作原理是通过构建有序序列,对于未排序数据, 2 //在已排序序列中从后向前扫描,找到相应位置并插入。 3 //具体算法描述如下: 4 5 //1.从第一个元素开始,该元素可以认为已经被排序; 6 //2.取出下一个元素,在已经排序的元素序列中从后向前扫描; 7 //3.如果该元素(已排序)大于新元素,将该元素移到下一位置; 8 //4.重复步骤3,直到找到已排序的元素小于或者等于新元素的位置; 9 //5.将新元素插入到该位置后; 10 //6.重复步骤2~5 11 //其实有点像我们玩扑克理牌的时候,不过我们可以观察,就不会这么死的步骤了 12 #include<bits/stdc++.h> 13 using namespace std; 14 const int N = 1e4 + 10; 15 16 int a[N]; 17 18 void Insertion_sort(int *arr,int len) 19 { 20 for(int i = 1;i < len;i++) 21 { 22 int Invalue = arr[i+1];//要插入的值 23 int curIndex = i;//当前位置 24 //找到插入的位置 25 while(curIndex >= 1 && arr[curIndex] > Invalue) 26 { 27 arr[curIndex + 1] = arr[curIndex]; 28 --curIndex; 29 } 30 //在后面插入值 31 arr[curIndex + 1] = Invalue; 32 } 33 } 34 35 int main() 36 { 37 int n; 38 while(cin >> n) 39 { 40 for(int i = 1;i <= n;i++) 41 cin >> a[i]; 42 Insertion_sort(a,n); 43 puts("After Insertion_sort:"); 44 for(int i = 1;i <= n;i++) 45 cout << a[i] << " "[i == n]; 46 } 47 return 0; 48 }
希尔排序动图演示
希尔排序代码实现
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N = 1e4 + 10; 4 int a[N]; 5 6 void shell_sort(int *arr,int len) 7 { 8 if(arr == NULL || len <= 0) 9 return; 10 int cnt = 1; 11 for(int gap = len >> 1;gap > 0;gap >>= 1) 12 { 13 if(gap == 2) gap++; 14 cout << "gap = " << gap << endl; 15 for(int i = gap + 1;i <= len;i++) 16 { 17 cout << "i = " << i << endl; 18 int tem = arr[i]; 19 int j = i - gap; 20 while(arr[j] > tem && j >= 1) 21 { 22 cout << "j = " << j << endl; 23 arr[j+gap] = arr[j]; 24 j -= gap; 25 } 26 arr[j+gap] = tem; 27 } 28 // cout << cnt++ << ": "; 29 // for(int i = 1;i <= len;i++) 30 // cout << arr[i] << " "[i == len]; 31 } 32 } 33 //10 34 //49 38 65 97 76 13 27 49 55 04 35 int main() 36 { 37 int n; 38 while(cin >> n) 39 { 40 for(int i = 1;i <= n;i++) 41 cin >> a[i]; 42 shell_sort(a,n); 43 44 puts("After shell_sort:"); 45 for(int i = 1;i <= n;i++) 46 cout << a[i] << " "[i == n]; 47 } 48 return 0; 49 }
选择排序动态图演示
选择排序代码实现
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N = 1e5 + 10; 4 int a[N]; 5 //选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理 6 //首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置, 7 //然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。 8 //以此类推,直到所有元素均排序完毕。 9 void Selection_sort(int *arr,int len) 10 { 11 for(int i = 1;i < len;i++) 12 { 13 int Minindex = i; 14 for(int j = i + 1;j <= len;j++) 15 if(arr[j] < arr[Minindex]) 16 { 17 Minindex = j; 18 } 19 int tem = arr[Minindex]; 20 arr[Minindex] = arr[i]; 21 arr[i] = tem; 22 } 23 } 24 25 int main() 26 { 27 int n; 28 while(cin >> n) 29 { 30 for(int i = 1;i <= n;i++) 31 cin >> a[i]; 32 Selection_sort(a,n); 33 puts("After Selection_sort:"); 34 for(int i = 1;i <= n;i++) 35 cout << a[i] << " "[i == n]; 36 } 37 return 0; 38 }
堆排序动图演示
堆排序代码实现
1 //堆排序,是指利用堆这种数据结构所设计的一种排序算法。 2 //堆是一个近似完全二叉树的结构,并同时满足堆积的性质: 3 //即子结点的键值或索引总是小于(或者大于)它的父节点。 4 // 5 //步骤: 6 //在最小堆的数据结构中,堆中的最小值总是位于根节点 7 //在优先队列中使用堆的话堆中的最小值位于根节点 堆中定义以下几种操作: 8 //最小堆调整:将堆的末端子节点作调整,使得子节点永远大于父节点 9 //创建最小堆:将堆中的所有数据重新排序 10 // 11 //堆排序:移除位在第一个数据的根节点,并做最大堆调整的递归运算 12 //其实说白了就是一种有某种性质的数据结构 13 //然后你做什么改动,都必须通过调整来维护该性质 14 15 #include<bits/stdc++.h> 16 using namespace std; 17 const int N = 1e4 + 10; 18 int h[N]; 19 int n; 20 21 void Swap(int x,int y) 22 { 23 int tem = h[x]; 24 h[x] = h[y]; 25 h[y] = tem; 26 } 27 28 //传入一个向下调整的结点编号i 29 void shiftdown(int i) 30 { 31 int t,flag = 0;//t用于记录较大值结点编号,flag用于标记是否需要下调整 32 //当i有儿子,且需要调整是进行下面的操作 33 while(i*2 <= n && !flag ) 34 { 35 if(h[i] < h[i*2])//和左儿子比较 36 t = 2*i; 37 else t = i; 38 //如果有右儿子再比较 39 if(i*2 + 1 <= n) 40 { 41 if(h[t] < h[i*2 + 1]) 42 t = 2*i + 1; 43 } 44 45 if(i != t) 46 { 47 Swap(t,i); 48 i = t; 49 } 50 else flag = 1; 51 } 52 } 53 54 //传入需要向上调整的结点i 55 //void shiftup(int i) 56 //{ 57 // int flag = 0; 58 // if(i == 1) return; 59 // while(i != 1 && flag == 0) 60 // { 61 // if(h[i] < h[i/2]) 62 // Swap(i,i/2); 63 // else flag = 1; 64 // i = i/2;//更新结点 65 // } 66 //} 67 68 //建立最大堆,之后最大元素是h[1] 69 void creatHeap() 70 { 71 //完全二叉树有n/2个非叶结点 72 for(int i = n/2;i >= 1;i--) 73 shiftdown(i); 74 } 75 76 //int deleteMin() 77 //{ 78 // int t = h[1]; 79 // h[1] = h[n]; 80 // n--; 81 // shiftdown(1); 82 // return t; 83 //} 84 /* 85 从小到大排序的时候不建立最小堆而建立最大堆。最大堆建立好后, 86 最大的元素在h[ 1]。因为我们的需求是从小到大排序, 87 希望最大的放在最后。因此我们将h[1]和h[n]交换, 88 此时h[ n]就是数组中的最大的元素。请注意,交换后还需将h[1]向下调整以保持堆的特性。 89 OK现在最大的元素已经归位,需要将堆的大小减1即n--,然后再将h[ 1]和h[ n]交换 90 并将h[ 1]向下调整。如此反复,直到堆的大小变成1为止。此时数组h中的数就已经是排序好的了 91 */ 92 void heap_sort() 93 { 94 while(n > 1) 95 { 96 Swap(1,n); 97 n--; 98 shiftdown(1); 99 } 100 } 101 int main() 102 { 103 int i,num; 104 105 while(cin >> num) 106 { 107 for(int i = 1;i <= num;i++) 108 cin >> h[i]; 109 n = num; 110 creatHeap(); 111 heap_sort(); 112 113 for(int i = 1;i <= num;i++) 114 cout << h[i] << " "[i == num]; 115 } 116 return 0; 117 }
归并排序动图演示(二路归并)
归并排序代码实现
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N = 1e4 + 10; 4 //该算法的主要思想是对于两个已经有序的数组进行合并是简单的 5 //只需要对两个数组元素大小比较即可 6 //那么刚开始只需二分数组,分出来的两个小数组又递归地 7 //进行排序,然后有序的两个小数组就可以合并为一个大数组 8 //分治+二分 9 10 int a[N],t[N]; 11 12 void Merge_sort(int *arr,int *T,int l,int r) 13 { 14 //如果只有一个元素就不需要进行二分了 15 if(r - l >= 1) 16 { 17 int m = l + (r - l)/2; 18 19 //二分递归 20 Merge_sort(arr,T,l,m); 21 Merge_sort(arr,T,m+1,r); 22 23 int i = l,j = m + 1; 24 int nst = l; 25 26 //合并两个有序的小数组 27 while(i <= m || j <= r) 28 if(j > r || (i <= m && arr[i] < arr[j])) 29 T[nst++] = arr[i++]; 30 else T[nst++] = arr[j++]; 31 32 for(nst = l;nst <= r;nst++) 33 arr[nst] = T[nst]; 34 } 35 } 36 37 int main(){ 38 39 int n; 40 while(cin >> n) 41 { 42 for(int i = 1;i <= n;i++) 43 cin >> a[i]; 44 Merge_sort(a,t,1,n); 45 puts("After Merge_sort:"); 46 for(int i = 1;i <= n;i++) 47 cout << a[i] << " "[i == n]; 48 } 49 return 0; 50 }
计数排序动图演示
计数排序代码实现
1 #include<iostream> 2 #include<string.h> 3 #include<cstdio> 4 using namespace std; 5 6 const int N = 1e5 + 10; 7 int a[N],b[N]; 8 9 //这个算法的局限性,最大最小值之差太大就不行了,因为数组不可能开的很大 10 void Count_sort(int n, int* A,int *B,int l,int r) 11 { 12 int d = (r - l); 13 for (int i = 0; i <= d; i++) 14 b[i] = 0; 15 16 for (int i = 1; i <= n; i++) 17 b[a[i] - l]++; 18 } 19 20 int main() 21 { 22 int n; 23 while (cin >> n) 24 { 25 int r = -1e6,l = 1e6; 26 for (int i = 1; i <= n; i++) 27 { 28 cin >> a[i]; 29 if (a[i] > r) 30 r = a[i]; 31 if(a[i] < l) 32 l = a[i]; 33 } 34 int d = r - l; 35 Count_sort(n, a, b, l, r); 36 37 puts("After Count_sort:"); 38 for (int i = 0; i <= d; i++) 39 for (int j = 1; j <= b[i]; j++) 40 cout << i + l << " "; 41 puts(""); 42 } 43 return 0; 44 }
桶排序
桶排序代码实现
1 //算法描述: 2 //首先它是建立在计数排序的基础上 3 //你需要知道数列里的最大最小值 4 //然后自己定义桶的个数(有些人直接分为10个桶),然后每个桶对应一个区间 5 //把每个数放到对应的区间 6 //每个桶内部可以用其他排序算法来排, 7 //每个桶排序好之后,由于桶之间保存的数字大小区间不一样 8 //最后合并所有桶就得到有序序列了 9 //这份代码是别人写的,我本来想用一个二位数组写的, 10 //不过用链表写也不错,我是理解了他的了,还加了一些注释 11 //而且这个写法没有离散化,导致输入的数据不可以是负数 12 //而且桶内的排序相当于插入排序是n^2的复杂度,是不对的,总的复杂度 13 //居然是n^2,我表示这个不是真的桶排序 14 #include<bits/stdc++.h> 15 using namespace std; 16 const int N = 1e4 + 10; 17 int a[N]; 18 19 typedef struct node { 20 int key; 21 struct node* next; 22 }KeyNode; 23 24 void bucket_sort(int keys[], int size, int bucket_size) 25 { 26 KeyNode** bucket_table = (KeyNode**)malloc(bucket_size * sizeof(KeyNode*)); 27 28 for (int i = 0; i < bucket_size; i++) { //初始化每个桶 29 bucket_table[i] = (KeyNode*)malloc(sizeof(KeyNode)); 30 bucket_table[i]->key = 0; 31 bucket_table[i]->next = NULL; 32 } 33 34 for (int i = 0; i < size; i++) { 35 KeyNode* node = (KeyNode*)malloc(sizeof(KeyNode)); 36 node->key = keys[i]; 37 node->next = NULL; 38 39 int index = keys[i] / 10;//给数据分类的方法(关系到排序速度,很重要) 40 KeyNode* p = bucket_table[index]; 41 if (p->key == 0) { 42 p->next = node; 43 p->key++; 44 } 45 else { 46 while (p->next != NULL && p->next->key <= node->key) { 47 //新来的就找到自己的位置 48 //这里选择类插入排序的方式,其实是不对的,因为这样的方式相当与每个桶内又是 49 //n^2复杂度 50 p = p->next; 51 } 52 node->next = p->next; 53 p->next = node; 54 (bucket_table[index]->key)++;//这个桶当前数据量加一 55 } 56 } 57 58 KeyNode* k = NULL; 59 //遍历每个桶 60 for (int i = 0; i < bucket_size; i++) { 61 for (k = bucket_table[i]->next; k != NULL; k = k->next) { 62 printf("%d ", k->key); 63 } 64 } 65 } 66 67 int main() 68 { 69 int n; 70 while(cin >> n) 71 { 72 for(int i = 0;i < n;i++) 73 cin >> a[i]; 74 puts("After bucket_sort:"); 75 bucket_sort(a, n, 10); 76 } 77 return 0; 78 }
基数排序动态图演示
基数排序代码实现
1 #include<bits/stdc++.h> 2 using namespace std; 3 int a[100]; 4 int n, ma; 5 void work(int cur) { 6 int b[10] = { 0 }; 7 int c[100]; 8 for (int i = 0; i < n; i++) 9 b[(a[i] / cur) % 10]++; 10 11 for (int i = 1; i < 10; i++) 12 b[i] += b[i - 1];//前缀和,b[i]表示当前位小于等于i的数字有多少个 13 14 // 下面这个地方尤为关键为啥从n - 1开始,而不是从0开始 15 // 因为是从最低位开始调整位置的,前面已经在低位排好了,如果从0开始 16 // 如果当前位两个数字为0,那么他们的相对位置应该不变 17 // 从0开始就反了,顺序错了 18 19 for (int i = n - 1; i >= 0; i--) 20 { 21 //精髓所在 22 c[b[(a[i] / cur) % 10] - 1] = a[i]; 23 b[(a[i] / cur) % 10]--; 24 } 25 26 //复制一份给原始数据 27 for (int i = 0; i < n; i++) 28 a[i] = c[i]; 29 } 30 31 void radix_sort() { 32 //1代表各位的比较,10代表十位的比较,依此类推 33 for (int i = 1; ma / i > 0; i *= 10) 34 work(i); 35 } 36 37 int main() { 38 39 while (cin >> n) { 40 ma = 0; 41 for (int i = 0; i < n; i++) { 42 cin >> a[i]; 43 if(a[i] > ma) ma = a[i]; 44 } 45 puts("before sort"); 46 for (int i = 0; i < n; i++) 47 cout << a[i] << ‘ ‘; 48 puts(""); 49 radix_sort(); 50 puts("after radix_sort"); 51 for (int i = 0; i < n; i++) 52 cout << a[i] << ‘ ‘; 53 puts(""); 54 } 55 return 0; 56 }
最后各排序算法对比
以上是关于十大排序算法(原理及代码实现细节)的主要内容,如果未能解决你的问题,请参考以下文章