代码实现
时间复杂度:算法占用的时间(一般与数据数量呈正相关)。
空间复杂度:算法占用的空间(一般与数据数量呈正相关)。
算法稳定性:是指是否会交换值相等的两个数据的初始位置。
冒泡排序(BubbleSort)是一种入门级别的算法,较好理解。一般作为第一种算法被认识。
冒泡排序是一种稳定的排序。
平均时间按复杂度O(n*n) 【最好时间复杂度O(n),最坏时间复杂度O(n*n)】
空间复杂度O(1)
1、比较相邻的元素。如果第一个比第二个大,就交换他们两个。
2、对每一对相邻元素重复步骤1,从开始第一对到结尾的最后一对。每趟过后,排在最后的元素最大。
3、重复步骤2,直到剩下一个元素。
代码:
代码: 1 for(int i=0;i<n-1;i++) //n-1趟排序 2 { 3 for(int j=n-1;j>i;j--) //j>i因为i前面的元素已经排好了 4 { 5 int temp=0; 6 if(arrayA[j]<arrayA[j-1]) //比较相邻的两个元素,见步骤1 7 { 8 temp=arrayA[j]; 9 arrayA[j]=arrayA[j-1]; 10 arrayA[j-1]=temp; 11 }
选择排序其实是冒泡的升级,每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。
冒泡排序是一种稳定的排序。
平均时间按复杂度O(n*n) 【最好最坏均是O(n*n)】
空间复杂度O(1)
算法运作如下:
1、比较所有待排序元素。找到最小(最大)的元素。
2、将这个元素放入已排序数列的最后。
3、持续每次对待排序元素重复上面的步骤,直到没有待排序元素。
代码: 1 for(int i=0;i<n-1;i++) //n-1趟排序,因为最后只剩一个元素的时候不用再比较 2 { 3 int index=i; //索引值,记录当前已排序数列排列到的位置 4 for(int j=i+1;j<n;j++) //j从i+1开始,因为前面的元素已经排好了 5 { 6 if(arrayA[j]<arrayA[index]) 7 index=j; //每趟将待排序数据中的最小值的位置存放到index 8 } 9 10 //若该趟index指向的的最小值不在i处(最前面),则交换array[index]和array[i]的值 11 if (index!=i) 12 { 13 //交换数据 14 int temp = arrayA[i]; 15 arrayA[i] = arrayA[index]; 16 arrayA[index] = temp; 17 } 18 }
快速排序是对冒泡排序的一种改进。
快速排序是一种不稳定的排序。
平均时间按复杂度O(nlogn) 【最好时间复杂度O(nlogn),最坏时间复杂度O(n*n)】
空间复杂度O(nlogn)
算法运作如下:
1、以第一个元素作为key
2、对数组进行分区,使key左边元素的值都不大于key,右边的元素值都不小于key,最后将作为key的元素调整到排序后的正确位置。
3、将步骤2结束后的数列二分为key的左右两部分,递归快速排序,最终二分到只有一个元素,排序完成。
步骤2简图
全过程简图:
初始状态: 【49,38,65,97,76,13,27,49′】
步骤二: 【27,38,13】49【76,97,65,49′】
步骤三: 【13】27【38】【49′,65】76【97】
有序序列: 【13,27,38,49,49′,65,76,97】
#include<stdio.h> #include<stdlib.h> #define len 8 int Partition( int d[],int low,int high) { int t; t = d[low]; while(low<high) { while(low<high && d[high]>=t ) --high; d[low] = d[high]; while( low<high && d[low]<=t ) ++low; d[high] = d[low]; } d[low] = t; return low; // for(int k=0;k<len;k++) // printf("%d\n",d[k]); } void QSort(int *d,int low,int high) { //对顺序表中的子序列作快速排序 int pivotloc; if( low <high ) { pivotloc = Partition(d,low,high); QSort(d,low,pivotloc-1); QSort(d,pivotloc+1,high); } } void QuickSort(int *d) { QSort(d,0,len-1); } int main() { int d[len] = {49,38,65,97,76,13,27,49}; QuickSort(d); for(int k=0;k<len;k++) printf("%d\n",d[k]); return 0; }
参考:http://blog.csdn.net/lvyuan30276/article/details/9813705
“归并”的含义是将两个或两个以上的有序表组合成一个新的有序表。
速度仅次于快速排序(数量级相等,系数不同)。
一般用于对总体无序,但是各子项相对有序的数列。
归并排序是一种稳定的排序。
平均时间按复杂度O(nlogn) 【最好时间复杂度O(nlogn),最坏时间复杂度O(nlogn)】
空间复杂度O(n)
算法原理:
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,指向两个有序表的头
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
第四步:重复步骤三直到某一指针达到序列尾,将另一序列剩下的所有元素直接复制到合并序列尾。
第五步:将第四步重复,直到完成整个数列。
原理简图
代码: 1. #include <iostream> 2. using namespace std; 3. 4. const int maxSize = 100; 5. 6. /* 7. 函数名: Merge 8. 函数功能: 将有序的SR[begin, middle]和SR[middle+1, end]排序后存储到TR中。 9. 函数参数: int SR 原数组 10. int TR 目标数组 11. */ 12. void Merge(int SR[], int TR[], int begin, int middle, int end) 13. { 14. int i, j, k; 15. i = begin; 16. j = middle + 1; 17. k = begin; 18. while (i <= middle && j <= end) 19. { 20. if (SR[i] <= SR[j]) 21. { 22. TR[k] = SR[i]; 23. k++; 24. i++; 25. } 26. else 27. { 28. TR[k] = SR[j]; 29. k++; 30. j++; 31. } 32. } 33. 34. while (i <= middle) 35. { 36. TR[k] = SR[i]; 37. k++; 38. i++; 39. } 40. 41. while (j <= end) 42. { 43. TR[k] = SR[j]; 44. k++; 45. j++; 46. } 47. } 48. 49. void MergeSort(int SR[], int TR1[], int begin, int end) 50. { 51. if (begin == end) 52. { 53. TR1[begin] = SR[begin]; 54. } 55. else 56. { 57. int TR2[maxSize + 1]; 58. int middle = begin + (end - begin) / 2; /* 将SR[begin,end]平均分成SR[begin, middle]和SR[middle+1, t] */ 59. MergeSort(SR, TR2, begin, middle); /* 递归地将SR[begin, middle]归并为有序的TR2[begin, middle] */ 60. MergeSort(SR, TR2, middle+1, end); /* 递归地将SR[middle+1, end]归并为有序的TR2[middle+1, end] */ 61. Merge(TR2, TR1, begin, middle, end); /* 将TR2[begin, middle]和TR2[middle+1, end]归并到TR2[begin,end] */ 62. } 63. } 64. 65. int main() 66. { 67. int array[] = {50, 10, 90, 30, 70, 40, 80, 60, 20}; 68. MergeSort(array, array, 0, 8); 69. for (int i = 0; i < 9; i++) 70. { 71. cout << array[i] << " " ; 72. } 73. cout << endl; 74. }
参考:
http://blog.csdn.net/listener51/article/details/9839723 图解
http://blog.csdn.net/begginghard/article/details/9878433 算法
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
背景知识:1991年计算机先驱奖获得者、斯坦福大学计算机科学系教授罗伯特·弗洛伊德Robert W.Floyd和威廉姆斯J.Williams在1964年共同发明了著名的堆排序算法Heap Sort
时间复杂度为O(n*logn)【最好、最坏、平均三者,在数量级上相等】
空间复杂度O(1)【一个temp单元,用来辅助存储】
堆排序不稳定
算法描述:
1、 将原数据(N1,Nn)整理为大根堆
2、 将堆顶元素与排在线性最后的元素交换位置
3、 将数据(N1,Nn-1)重置为大根堆
4、 重复步骤2和步骤3,直到堆中仅剩一个元素
代码: 1. //用大根堆,排序后是从小到大排序(每次将最后一个元素与堆顶元素交换) 2. //假设数组data的下标从1开始 3. void HeapSort(int data[], int length) 4. { 5. int i; 6. for(i=length/2; i>=1; i--) //建立一个大根堆 7. HeapAdjust(data, i, length); 8. for(i=length; i>1; i--) 9. { 10. Swap(data, 1, i); //将根节点(此堆中最大元素)与最后一个元素交换位置 11. HeapAdjust(data, 1, i-1); //抛出堆中最后一个位置,重新整理为最大堆 12. } 13. } 14. 15. //data[s+1]¬¬—data[m]已满足堆的性质,现在调整data[s],使得data[s]—data[m]也成为一个大根堆 16. void HeapAdjust(int data[], int s, int m) 17. { 18. int temp, j; 19. temp = data[s]; 20. for(j=2*s; j<=m; j=j*2) 21. {//在data[i]的两个孩子data[2i]和data[2i+1] 中的较大者,跟data[i]进行比较,若孩子的值较大,则交换父节点和此孩子节点,保证其满足大根堆的性质。 22. if(j<m && data[j]<data[j+1]) //选择兄弟节点中的较大者 23. j++; 24. if(temp >= data[j]) //如果该节点小于父节点,则符合条件,跳出 25. break; 26. data[s] = data[j]; //如果该节点的值大于父节点,进行值的交换 27. s = j; 28. } 29. data[s] = temp; //此时辅助空间的值重新为父节点 30. }
桶排序特别适合数据随机分布在域上的情况。
其思想就是把区间[min,max]划分成n个相同大小的桶,然后将所有数据放到对应的桶中去(sum放到num/n+1号桶中)。然后对各个桶中的数进行排序(此处算法不做限制),最后按次序把各桶中的元素列出来即可。
数据随机分配在域上的情况下,
平均时间复杂度为线性的O(N+C),其中C=N*(logN-logM)【最好时间复杂度为O(N),但极费空间;最坏时间复杂度为子排序算法的复杂度】
空间复杂度为O(B*N),其中B是桶的个数
代码 1.分组 2.使用其他通用排序算法对各个桶内元素排序 代码略