内部排序法小结

1.冒泡排序(Bubble Sort)

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

 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 )。

 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)。

 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)。

 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)。

 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)。

  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/

 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 }
时间: 2024-10-10 19:54:33

内部排序法小结的相关文章

内部排序算法小结

内部排序算法主要分为插入类排序.交换类排序和选择类排序,它们在性能上的差异主要体现在时间复杂度.空间复杂度和稳定性.各种排序算法都会进行元素间的比较和移动,时间复杂度主要由整个排序过程中的比较次数和移动次数决定.空间复杂度体现在除了待排序记录本身所占的空间,排序过程中占用了多少辅助空间. 1.插入类排序 直接插入排序 如果待排序记录之间是顺序排列,此时整个排序过程中元素比较的次数为n-1次,移动次数为0次.如果待排序记录之间是逆序排列,第i趟排序比较次数为i,移动的次数为i+1,其中i的范围是2

内部排序算法(一):交换排序(冒泡排序,快速排序)

这是我的博文系列<内部排序算法>的第一篇.所谓排序,就是要整理文件中的记录,使之按关键字递增(或递减)次序排列起来.所谓内部排序,是指在排序过程中,若整个文件都是放在内存中处理,排序时不涉及数据的内.外存交换(外排序的定义则相反). 内部排序法按照策略可以划分为五类:插入排序.选择排序.交换排序.归并排序和分配排序.待排文件的存储方式采用顺序表(或直接用向量)作为存储结构(其他的存储结构还有以链表作为存储结构等). 在这个系列的博文中,我按照排序算法的给出,排序算法的分析(包括算法的时空复杂度

php排序介绍_冒泡排序_选择排序法_插入排序法_快速排序法

这里我们介绍一些常用的排序方法,排序是一个程序员的基本功,所谓排序就是对一组数据,按照某个顺序排列的过程. 充效率看 冒泡排序法<选择排序法<插入排序法 排序分两大类: 内部排序法 交换式排序法 冒泡法 基本思想: 冒泡排序法 案例: 1234567891011121314151617181920212223242526 //简单的$arr=array(0,5,-1); //现在我们把函数毛片封装成函数,利用以后使用//数组默认传递的是值,不是地址,&是地址符function bubb

常用排序算法小结

1 #include <stdio.h> 2 #include <stdlib.h> 3 4 5 //the basic bubble sort 6 void maopao1(int *num,int len) 7 { 8 int i,j; 9 int temp; 10 for (i = 0; i < len-1; ++i) 11 { 12 for (j = i+1; j<len; ++j) 13 { 14 if (num[i]>num[j]) 15 { 16 t

数据结构6种内部排序算法的比较

1.需求分析 (1)输入数据的形式为:伪随机数产生程序产生,且每次输入数不少于100个,至少要用5组不同的输入数据 (2)输出的形式为:输出关键字参加的比较次数和关键字的移动次数(关键字交换计为3次移动)的数据 (3)程序能达到的功能:对起泡排序,直接插入排序,简单选择排序,快速排序,希尔排序,堆排序这6种常用的内部排序算法进行比较,比较的指标为有关键字参加的比较次数和关键字的移动次数(关键字交换计为3次移动) (4)测试数据:正确输入为由伪随机数产生程序产生100个随机数,然后输出比较结果,错

10-11-基数排序-内部排序-第10章-《数据结构》课本源码-严蔚敏吴伟民版

课本源码部分 第10章  内部排序 - 基数排序 ——<数据结构>-严蔚敏.吴伟民版        源码使用说明  链接??? <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明        课本源码合辑  链接??? <数据结构>课本源码合辑        习题集全解析  链接??? <数据结构题集>习题解析合辑        本源码引入的文件  链接? Status.h.Scanf.c        相关测试数据下载  链接? 数据

直接插入排序(内部排序)

1 package com.trfizeng.insertionsort; 2 3 /** 4 * 5 * @author trfizeng 内部排序 插入排序 --- 直接插入排序(Straight Insertion Sort) 6 * 7 */ 8 public class StraightInsertionSort { 9 public static int[] straightInsertionSort(int[] array) { 10 // 对传来的待排序数组进行合法验证 11 i

简单的选择排序(内部排序)

1 /** 2 * 3 */ 4 package com.trfizeng.selectionsort; 5 6 /** 7 * @author trfizeng 内部排序 选择排序—简单选择排序(Simple Selection Sort) 8 */ 9 public class SimpleSelectionSort { 10 11 /** 12 * 每次选择一个最小记录放在前面去 13 */ 14 public static int[] simpleSelectionSort(int[]

内部排序-第10章-《数据结构题集》习题解析-严蔚敏吴伟民版

//**留坑待填**// 一.基础知识题 10.1?以关键码序列(503,087,512,061,908,170,897,275,653,426)为例,手工执行以下排序算法,写出每一趟排序结束时的关键码状态: (1)直接插入排序:                            (2)希尔排序(增量d[1]=5): (3)快速排序:                                  (4)堆排序: (5)归并排序: