内部排序法小结

1.冒泡排序(Bubble Sort)

冒泡排序方法是最简单的排序方法。这种方法的基本思想是,将待排序的元素看作是竖着排列的“气泡”,较小的元素比较轻,从而要往上浮。在冒泡排序算法中我们要对这个“气泡”序列处理若干遍。所谓一遍处理,就是自底向上检查一遍这个序列,并时刻注意两个相邻的元素的顺序是否正确。如果发现两个相邻元素的顺序不对,即“轻”的元素在下面,就交换它们的位置。显然,处理一遍之后,“最轻”的元素就浮到了最高位置;处理二遍之后,“次轻”的元素就浮到了次高位置。在作第二遍处理时,由于最高位置上的元素已是“最轻”元素,所以不必检查。一般地,第i遍处理时,不必检查第i高位置以上的元素,因为经过前面i-1遍的处理,它们已正确地排好序。
冒泡排序是稳定的。算法时间复杂度是O(n^2)。

[cpp]  view plain copy
  1. //冒泡排序(相邻比较法)  
  2. void BubbleSort(int a[],int n)  
  3. {  
  4.     int i,j;  
  5.     int temp;  
  6.     for(i = 0; i < n-1; i++)  
  7.         for(j = 0; j < n-i-1; j++)  
  8.             if(a[j] > a[j+1])  
  9.             {  
  10.                 temp = a[j];  
  11.                 a[j] = a[j+1];  
  12.                 a[j+1] = temp;  
  13.             }  
  14. }  
  15. //改进的冒泡排序  
  16. void ImprovedBubbleSort(int a[], int n)  
  17. {  
  18.     int i,j;  
  19.     int temp;  
  20.     bool change = false;  
  21.     for (i = 0; i < n-1; i++)  
  22.     {  
  23.         change = false;  
  24.         for (int j = 0; j < n-i-1; j++)  
  25.         if (a[j] > a[j+1])  
  26.         {  
  27.             temp = a[j];  
  28.             a[j] = a[j+1];  
  29.             a[j+1] = temp;  
  30.             change = true;  
  31.         }  
  32.         if ( !change ) break;  
  33.     }  
  34. }  

2.选择排序(Selection Sort)

选择排序的基本思想是对待排序的记录序列进行n-1遍的处理,第i遍处理是将L[i..n]中最小者与L[i]交换位置。这样,经过i遍处理之后,前i个记录的位置已经是正确的了。
选择排序是不稳定的。算法复杂度是O(n^2 )。

[cpp]  view plain copy
  1. //选择排序  
  2. void SelectSort(int a[],int n)  
  3. {  
  4.     int temp;  
  5.     int i,j;  
  6.     for (i = 0; i < n; i++)  
  7.     {  
  8.         int k = i;  
  9.         for (j = i+1; j < n; j++)  
  10.             if (a[j] < a[k]) k = j;  
  11.         if(k != i)  
  12.         {  
  13.            temp = a[i];  
  14.            a[i] = a[k];  
  15.            a[k] = temp;  
  16.         }  
  17.     }  
  18. }  

3.插入排序(Insertion Sort)

插入排序的基本思想是,经过i-1遍处理后,L[1..i-1]己排好序。第i遍处理仅将L[i]插入L[1..i-1]的适当位置,使得L[1..i]又是排好序的序列。要达到这个目的,我们可以用顺序比较的方法。首先比较L[i]和L[i-1],如果L[i-1]<=L[i],则L[1..i]已排好序,第i遍处理就结束了;否则交换L[i]与L[i-1]的位置,继续比较L[i-1]和L[i-2],直到找到某一个位置j(1<=j<=i-1),使得L[j] <=L[j+1]时为止。
直接插入排序是稳定的。算法时间复杂度是O(n^2)。

[cpp]  view plain copy
  1. //插入排序  
  2. void InsertSort(int a[], int n)  
  3. {  
  4.     int i, j;  
  5.     int temp;  
  6.     for (i = 1; i < n; i++)  
  7.     {  
  8.         temp = a[i];  
  9.         j = i -1;  
  10.         while(j >= 0 && a[j] > temp;)  
  11.         {  
  12.             a[j+1] = a[j];  
  13.             --j;  
  14.         }  
  15.         a[j+1] = temp;  
  16.     }  
  17. }  
  18.   
  19. //递归的插入排序  
  20. void RecursiveInsertSort(int a[], int n)  
  21. {  
  22.     int i, j, key;  
  23.     if(n > 1)  
  24.     {  
  25.         RecursiveInsertSort(a,n-1);  
  26.     }  
  27.     key = a[n-1];  
  28.     i = n-2;  
  29.     while(i >= 0 && a[i] > key)  
  30.     {  
  31.         a[i+1] = a[i];  
  32.         i--;  
  33.     }  
  34.     a[i+1] = key;  
  35. }  
  36.   
  37. //折半插入排序  
  38. void BinInsertSort(int a[], int n)  
  39. {  
  40.     int i,j;  
  41.     for (i = 1; i < n; i++)  
  42.     {  
  43.         // 在a[0..i-1]中折半查找插入位置使a[high]<=a[i]<a[high+1..i-1]  
  44.         int low = 0, high = i-1, m = 0;  
  45.         while (low <= high)  
  46.         {  
  47.             m = m + (high-low)>>1;  
  48.             if (a[i] < a[m]) high = m-1;  
  49.             else low = m+1;  
  50.         }  
  51.         // 向后移动元素a[high+1..i-1],在a[high+1]处插入a[i]  
  52.         int x = a[i];  
  53.         for (j = i-1; j > high; j--)  
  54.             a[j+1] = a[j];  
  55.         a[high+1] = x;  // 完成插入  
  56.     }  
  57. }  

4.希尔排序(Shell Sort)

先将待排序列分割成若干个子序列,分别进行直接插入排序,基本有序后再对整个序列进行直接插入排序。
希尔排序是不稳定的。时间复杂度大约为O(n^3/2)。

[cpp]  view plain copy
  1. //希尔排序:shell排序的核心仍然使用插入排序  
  2. void ShellSort(int a[], int n)  
  3. {  
  4.     int dk = n/2;  
  5.     int i,j;  
  6.     while (dk >= 1)  
  7.     {  
  8.         // 一趟希尔排序,对dk个序列分别进行插入排序  
  9.         for (i = dk; i < n; ++i)  
  10.         {  
  11.             int x = a[i];  
  12.             for (j = i-dk; j >= 0 && a[j] > x; j -= dk )  
  13.                 a[j+dk] = a[j];  
  14.             a[j+dk] = x;  
  15.         }  
  16.         dk = dk/2;  // 缩小增量  
  17.     }  
  18. }  

5.堆排序(Heap Sort)

堆排序是一种树形选择排序,在排序过程中,将A[n]看成是完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系来选择最小的元素。对N个元素从小到大排序建立大根堆,然后交换堆顶与最后一个元素,将剩下的N-1个元素调整为大根堆,执行N-1此这样的操作。
堆排序是不稳定的。算法时间复杂度O(nlogn)。

[cpp]  view plain copy
  1. //调整大根堆  
  2. void HeapAdjust(int data[],int nStart, int nLen)  
  3. {  
  4.     int nMaxChild = 0;  
  5.     int Temp;  
  6.   
  7.     while ((2*nStart+1) < nLen)  
  8.     {  
  9.         nMaxChild = 2*nStart+1;  
  10.         if ( (2*nStart+2) < nLen)  
  11.         {  
  12.             //比较左子树和右子树,记录最大值的Index  
  13.             if (data[2*nStart+1] < data[2*nStart+2])  
  14.             {  
  15.                 nMaxChild = 2*nStart+2;  
  16.             }  
  17.         }  
  18.         //change data  
  19.         if (data[nStart] < data[nMaxChild])  
  20.         {  
  21.             //交换nStart与nMaxChild的数据  
  22.             Temp = data[nStart];  
  23.             data[nStart] = data[nMaxChild];  
  24.             data[nMaxChild] = Temp;  
  25.   
  26.             //堆被破坏,需要重新调整  
  27.             nStart = nMaxChild;  
  28.         }  
  29.         else  
  30.         {  
  31.             //比较左右孩子均小则堆未破坏,不再需要调整  
  32.             break;  
  33.         }  
  34.     }  
  35. }  
  36.   
  37. //堆排序 从小到大排序建立大顶堆  
  38. void HeapSort(int data[],int nLen)  
  39. {  
  40.     int i;  
  41.     int nTemp;  
  42.     //建立堆  
  43.     for (i = nLen/2-1; i >= 0; i--)  
  44.     {  
  45.         HeapAdjust(data, i, nLen);  
  46.     }  
  47.     for (i = nLen-1; i > 0; i--)  
  48.     {  
  49.         //交换堆顶元素和最后一个元素  
  50.         nTemp = data[0];  
  51.         data[0] = data[i];  
  52.         data[i] = nTemp;  
  53.   
  54.         //将data[0...i]重写建成大根堆  
  55.         HeapAdjust(data, 0, i);  
  56.     }  
  57. }  

6.快速排序(Quick Sort)

快速排序是对冒泡排序的一种本质改进。它的基本思想是通过一趟扫描后,使得排序序列的长度能大幅度地减少。在冒泡排序中,一次扫描只能确保最大数值的数移到正确位置,而待排序序列的长度可能只减少1。快速排序通过一趟扫描,就能确保某个数(以它为基准点吧)的左边各数都比它小,右边各数都比它大。然后又用同样的方法处理它左右两边的数,直到基准点的左右只有一个元素为止。

快速排序是不稳定的。最理想情况算法时间复杂度O(nlog2n),最坏O(n^2)。

[cpp]  view plain copy
  1. //快速排序  
  2. void QuickSort(int a[], int low, int high)  
  3. {  
  4.     if (low < high)  
  5.     {  
  6.         // 划分  
  7.         int pivot = a[low];  
  8.         int i = low; int j = high;  
  9.         while (i < j)  
  10.         {  
  11.             while (i<j && a[j] >= pivot)  j--;  
  12.             a[i] = a[j];  
  13.             while (i<j && a[i] <= pivot)  i++;  
  14.             a[j] = a[i];  
  15.         }  
  16.         a[i] = pivot;  
  17.         // 对子序列快排  
  18.         QuickSort(a, low, i-1);  
  19.         QuickSort(a, i+1, high);  
  20.     }  
  21. }  
  22.   
  23. //快速排序法的划分操作  
  24. int Partition(int vec[],int low,int high)  
  25. {  
  26.      //任选元素作为轴,这里选首元素  
  27.      int pivot = vec[low];  
  28.      while(low < high)  
  29.      {  
  30.          while(low < high && vec[high] >= pivot)  
  31.              high--;  
  32.          vec[low] = vec[high];  
  33.          while(low < high && vec[low] <= pivot)  
  34.              low++;  
  35.          vec[high] = vec[low];  
  36.      }  
  37.      //此时low==high  
  38.      vec[low] = pivot;  
  39.      return low;  
  40. }  
  41.   
  42. //in-place partition algorithm  
  43. //http://en.wikipedia.org/wiki/Quicksort  
  44. int in_place_partition(int* array, int left, int right)  
  45. {  
  46.     int index = left;  
  47.     int pivot = array[index];  
  48.     swap(array[index], array[right]);  
  49.     for (int i=left; i<right; i++)  
  50.     {  
  51.         if (array[i] < pivot)    //升序  
  52.         {  
  53.             swap(array[index], array[i]);  
  54.             ++index;  
  55.         }  
  56.     }  
  57.     swap(array[right], array[index]);  
  58.     return index;  
  59. }  
  60.   
  61. void Qsort(int* array, int left, int right)  
  62. {  
  63.     if (left >= right)  
  64.         return;  
  65.     int index = Partition(array, left, right);  
  66.     Qsort(array, left, index - 1);  
  67.     Qsort(array, index + 1, right);  
  68. }  
  69.   
  70. //非递归快速排序  
  71. void QuickSort2(int vec[],int low,int high)  
  72. {  
  73.     stack<int> st;  
  74.     if(low < high)  
  75.     {  
  76.         int mid = Partition(vec,low,high);  
  77.         if(low < mid-1)  
  78.         {  
  79.              st.push(low);  
  80.              st.push(mid-1);  
  81.          }  
  82.          if(mid+1 < high)  
  83.          {  
  84.              st.push(mid+1);  
  85.              st.push(high);  
  86.          }  
  87.          //用栈保存每个待排序子串的首尾元素下标,下一次循环时取出这个范围,对这段子序列进行partition操作  
  88.          while(!st.empty())  
  89.          {  
  90.              int q = st.top();  
  91.              st.pop();  
  92.              int p=st.top();  
  93.              st.pop();  
  94.              mid = Partition(vec,p,q);  
  95.              if(p < mid-1)  
  96.              {  
  97.                  st.push(p);  
  98.                  st.push(mid-1);  
  99.              }  
  100.              if(mid+1<q)  
  101.              {  
  102.                  st.push(mid+1);  
  103.                  st.push(q);  
  104.              }  
  105.          }  
  106.      }  
  107. }  

8.归并排序(Merge Sort)

基本思想是合并两个有序表,设有两个有序(升序)序列存储在同一数组中相邻的位置上,不妨设为A[l..m],A[m+1..h],将它们归并为一个有序数列,并存储在A[l..h]。
归并排序的时间复杂度无论是在最好情况下还是在最坏情况下均是O(nlog2n)。

归并排序在最坏的情况下都是O(NlogN)的时间复杂度,缺点是Merge的时候要有O(N)的额外的空间,如何改进?使用In-place Merge Sort:http://blog.ibread.net/345/in-place-merge-sort/

[cpp]  view plain copy
  1. //将有序序列a[low..mid]和a[mid+1..high]归并到a[low..high]。  
  2. void Merge(int a[], int low, int mid, int high)  
  3. {  
  4.     // 归并到b[]  
  5.     int i = low;  
  6.     int j = mid+1;  
  7.     int k = 0;  
  8.     int *b = new int[high-low+1];  
  9.     while (i <= mid && j <= high)  
  10.     {  
  11.         if (a[i] <= a[j]) { b[k++] = a[i++]; }  
  12.         else  { b[k++] = a[j++]; }  
  13.     }  
  14.     // 归并剩余元素  
  15.     while (i <= mid)  b[k++] = a[i++];  
  16.     while (j <= high)  b[k++] = a[j++];  
  17.     // 从b[]复制回a[]  
  18.     for(i = 0; i <= high-low; ++i)  
  19.         a[low+i] = b[i];  
  20.     delete []b;  
  21. }  
  22.   
  23. //归并排序  
  24. //http://en.wikipedia.org/wiki/Mergesort  
  25. void MergeSort(int a[], int low, int high)  
  26. {  
  27.     if(low >= high)  return;  
  28.     else  
  29.     {  
  30.         int mid = (low+high)/2;  
  31.         MergeSort(a,low,mid);  
  32.         MergeSort(a,mid+1,high);  
  33.         Merge(a,low,mid,high);  
  34.     }  
  35. }  
  36.   
  37. //自底向上的归并排序  
  38. void MergeSort2(int a[], int n)  
  39. {  
  40.     int s,i,t = 1;  
  41.     while(t < n)  
  42.     {  
  43.         s = t;  t = s*2;  
  44.         for(i=0; i+t<=n; i+=t)  
  45.             Merge(a,i,i+s-1,i+t-1);  
  46.         if(i+s < n)  
  47.             Merge(a,i,i+s-1,n-1);  
  48.     }  
  49. }  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tiny丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值