zoukankan      html  css  js  c++  java
  • 数据结构学习笔记06排序 (冒泡、插入、希尔、堆排序、归并排序)

    前提
    void X_Sort ( ElementType A[], int N )
      大多数情况下,为简单起见,讨论从小大的整数排序
      N是正整数
      只讨论基于比较的排序(> = < 有定义)
      只讨论内部排序
      稳定性:任意两个相等的数据,排序前后的相对位置不发生改变

    1.冒泡排序

    (从小到大排序)

    物理意义:大泡泡往下沉,小泡泡往上冒

    每次比较相邻两个泡泡,符合条件,交换位置,每一轮比较完,最大的泡泡沉到最底下。

    最好情况:顺序T = O( N )
    最坏情况:逆序T = O( N^2 )

    稳定

     1 #include <stdio.h>
     2 
     3 typedef int ElementType;
     4 
     5 void BubbleSort(ElementType A[], int N)
     6 {
     7     for(int P = N-1; P >= 0; P--) {
     8         int flag = 0;
     9         for(int i = 0; i < P; i++) {
    10             if( A[i] > A[i+1] ) {
    11                 ElementType temp = A[i];    //swap A[i] A[i+1]
    12                 A[i] = A[i+1];
    13                 A[i+1] = temp;
    14                 flag = 1;
    15             }
    16         }
    17         if(flag == 0)
    18             break;
    19     }
    20 }
    21 
    22 int main()
    23 {
    24     int a[] = {34,8,64,51,32,21};
    25     BubbleSort(a,6);
    26     for(int i = 0; i < 6; i++)
    27         printf("%d ",a[i]);
    28     
    29     return 0;
    30 } 
    BubbleSort

    2.插入排序

     (从小到大排序) 

     和打扑克摸牌差不多,每次摸牌从最后往前依次进行比较,需插入的牌小,往前比较,找到合适位置插入。

    最好情况:顺序T = O( N )
    最坏情况:逆序T = O( N^2 )

     稳定

     1 #include <stdio.h>
     2 
     3 typedef int ElementType;
     4 
     5 void InsertionSort(ElementType A[], int N)
     6 {     
     7     int i;
     8     for (int P = 1; P < N; P++ ) {
     9         ElementType temp = A[P];     //取出未排序序列中的第一个元素
    10         for (i = P; i > 0 && A[i-1] > temp; i-- )
    11             A[i] = A[i-1];             //依次与已排序序列中元素比较并右移
    12         A[i] = temp; 
    13     }
    14 }
    15 
    16 int main()
    17 {
    18     int a[] = {34,8,64,51,32,21};
    19     InsertionSort(a,6);
    20     for(int i = 0; i < 6; i++)
    21         printf("%d ",a[i]);
    22     return 0;
    23 } 
    InsertionSort

    3.希尔排序

    每5 3 1间隔数进行插入排序。

    5 3 1成为增量序列。

      定义增量序列DM > DM-1 > … > D1 = 1
      对每个Dk 进行“Dk-间隔”排序( k = M, M-1, … 1 )
    “Dk-间隔”有序的序列,在执行“Dk-1-间隔”排序后,仍然是“Dk-间隔”有序的

    原始希尔排序DM = [N / 2]向下取整 , Dk = [D(k+1) / 2]向下取整

    最坏情况: T =Ο( N^2 )   不稳定

    增量元素不互质,则小增量可能根本不起作用。

    更多增量序列
      Hibbard 增量序列
        Dk = 2^k – 1 — 相邻元素互质
        最坏情况: T = O ( N^ 3/2 )
        猜想:Tavg = O ( N^ 5/4 )
      Sedgewick增量序列
        {1, 5, 19, 41, 109, … }
          9*4^i – 9*2^i + 1 或4^i – 3*2^i + 1
        猜想:Tavg = O ( N^ 7/6 ),Tworst = O ( N^ 4/3 )

     1 #include <stdio.h>
     2 
     3 typedef int ElementType;
     4 
     5 /* 原始希尔排序 */ 
     6 void Shell_Sort(ElementType A[], int N)
     7 {
     8     int i;
     9     for(int D = N/2; D > 0; D/=2) {
    10         for(int P = D; P < N; P++) {
    11             ElementType temp = A[P];
    12             for(i = P; i >= D && A[i-D]>temp; i-=D)
    13                 A[i] = A[i-D];
    14             A[i] = temp;
    15         }
    16     }
    17 }
    18 
    19 /* 希尔排序 - 用Sedgewick增量序列 */
    20 void ShellSort(ElementType A[], int N)
    21 { 
    22      int Si, i;
    23      /* 这里只列出一小部分增量 */
    24      int Sedgewick[] = {929, 505, 209, 109, 41, 19, 5, 1, 0};
    25       
    26      for ( Si = 0; Sedgewick[Si] >= N; Si++ ) 
    27          ; /* 初始的增量Sedgewick[Si]不能超过待排序列长度 */
    28  
    29      for (int D = Sedgewick[Si]; D > 0; D = Sedgewick[++Si])
    30          for (int P = D; P < N; P++ ) {         //插入排序
    31              ElementType temp = A[P];
    32              for(i = P; i >= D && A[i-D]>temp; i-=D)
    33                  A[i] = A[i-D];
    34              A[i] = temp;
    35          }
    36 }
    37 
    38 int main()
    39 {
    40     int a[] = {34,8,64,51,32,21};
    41     Shell_Sort(a,6);
    42     ShellSort(a,6);
    43     for(int i = 0; i < 6; i++)
    44         printf("%d ",a[i]);
    45     return 0;
    46 } 
    ShellSort

    4.堆排序

    (从小到大排序) 

    首先将堆调整为最大堆,堆顶元素为数组最大元素在A[0]位置,与A[N]交换位置。找到最大元素,将其放在最后。

    再调整为最大堆,且堆的大小-1,为N-1。依次执行。

      定理:堆排序处理N个不同元素的随机排列的平均比较次数是2N logN - O(Nlog logN) 。  不稳定
      虽然堆排序给出最佳平均时间复杂度,但实际效果不如用Sedgewick增量序列的希尔排序。

     1 #include <stdio.h>
     2 
     3 typedef int ElementType;
     4 
     5 void Swap( ElementType *a, ElementType *b )
     6 {
     7     ElementType t = *a;
     8     *a = *b; 
     9     *b = t;
    10 }
    11 /* 改编PercDown( MaxHeap H, int p )*/
    12 void PercDown( ElementType A[], int p, int N )
    13 { 
    14   /* 将N个元素的数组中以A[p]为根的子堆调整为最大堆 */
    15     int Parent, Child;
    16  
    17     ElementType X = A[p]; /* 取出根结点存放的值 */
    18     for( Parent=p; (Parent*2+1) < N; Parent=Child ) {
    19         Child = Parent * 2 + 1;
    20         if( (Child != N-1) && (A[Child] < A[Child+1]) )
    21             Child++;  /* Child指向左右子结点的较大者 */
    22         if( X >= A[Child] ) break; /* 找到了合适位置 */
    23         else  /* 下滤X */
    24             A[Parent] = A[Child];
    25     }
    26     A[Parent] = X;
    27 }
    28  
    29 void HeapSort(ElementType A[], int N) 
    30 { 
    31      for(int i = N/2-1; i >= 0; i--)/* 建立最大堆 */
    32          PercDown( A, i, N );
    33       
    34      for(int i = N-1; i > 0; i--) {
    35          /* 删除最大堆顶 */
    36          Swap(&A[0], &A[i] ); 
    37          PercDown(A, 0, i);
    38      }
    39 }
    40 
    41 int main()
    42 {
    43     int a[] = {34,8,64,51,32,21};
    44     HeapSort(a,6); 
    45     for(int i = 0; i < 6; i++)
    46         printf("%d ",a[i]);
    47     return 0;
    48 } 
    HeapSort

    5.归并排序

    归并排序一般不作内排序,在外排序中用

    核心:有序子列的归并

     1 /* L = 左边起始位置, R = 右边起始位置, RightEnd = 右边终点位置*/
     2 void Merge( ElementType A[], ElementType TmpA[], int L, int R, int RightEnd )
     3 { /* 将有序的A[L]~A[R-1]和A[R]~A[RightEnd]归并成一个有序序列 */
     4 
     5      int LeftEnd = R - 1; /* 左边终点位置 */
     6      int temp = L;         /* 有序序列的起始位置 */
     7      int NumElements = RightEnd - L + 1;
     8       
     9      while( L <= LeftEnd && R <= RightEnd ) {
    10          if ( A[L] <= A[R] )
    11              TmpA[temp++] = A[L++]; /* 将左边元素复制到TmpA */
    12          else
    13              TmpA[temp++] = A[R++]; /* 将右边元素复制到TmpA */
    14      }
    15  
    16      while( L <= LeftEnd )
    17          TmpA[temp++] = A[L++]; /* 直接复制左边剩下的 */
    18      while( R <= RightEnd )
    19          TmpA[temp++] = A[R++]; /* 直接复制右边剩下的 */
    20           
    21      for(int i = 0; i < NumElements; i++, RightEnd -- )
    22          A[RightEnd] = TmpA[RightEnd]; /* 将有序的TmpA[]复制回A[] */
    23 }
    Merge

    递归算法

     

     分而治之 

     T( N ) = O( N logN )

     稳定

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 typedef int ElementType;
     4 
     5 /* 归并排序 - 递归实现 */
     6  
     7 /* L = 左边起始位置, R = 右边起始位置, RightEnd = 右边终点位置*/
     8 void Merge( ElementType A[], ElementType TmpA[], int L, int R, int RightEnd )
     9 { /* 将有序的A[L]~A[R-1]和A[R]~A[RightEnd]归并成一个有序序列 */
    10 
    11      int LeftEnd = R - 1; /* 左边终点位置 */
    12      int temp = L;         /* 有序序列的起始位置 */
    13      int NumElements = RightEnd - L + 1;
    14       
    15      while( L <= LeftEnd && R <= RightEnd ) {
    16          if ( A[L] <= A[R] )
    17              TmpA[temp++] = A[L++]; /* 将左边元素复制到TmpA */
    18          else
    19              TmpA[temp++] = A[R++]; /* 将右边元素复制到TmpA */
    20      }
    21  
    22      while( L <= LeftEnd )
    23          TmpA[temp++] = A[L++]; /* 直接复制左边剩下的 */
    24      while( R <= RightEnd )
    25          TmpA[temp++] = A[R++]; /* 直接复制右边剩下的 */
    26           
    27      for(int i = 0; i < NumElements; i++, RightEnd -- )
    28          A[RightEnd] = TmpA[RightEnd]; /* 将有序的TmpA[]复制回A[] */
    29 }
    30 /* 核心递归排序函数 */ 
    31 void Msort( ElementType A[], ElementType TmpA[], int L, int RightEnd )
    32 { 
    33      int Center;
    34       
    35      if ( L < RightEnd ) {
    36           Center = (L+RightEnd) / 2;
    37           Msort( A, TmpA, L, Center );              /* 递归解决左边 */ 
    38           Msort( A, TmpA, Center+1, RightEnd );     /* 递归解决右边 */  
    39           Merge( A, TmpA, L, Center+1, RightEnd );  /* 合并两段有序序列 */ 
    40      }
    41 }
    42 /* 归并排序接口函数 */
    43 void MergeSort( ElementType A[], int N )
    44 { 
    45      ElementType *TmpA;
    46      TmpA = (ElementType *)malloc(N*sizeof(ElementType));
    47       
    48      if ( TmpA != NULL ) {
    49           Msort( A, TmpA, 0, N-1 );
    50           free( TmpA );
    51      }
    52      else printf( "空间不足" );
    53 }
    54 
    55 int main()
    56 {
    57     int a[] = {34,8,64,51,32,21};
    58     MergeSort(a,6);
    59     for(int i = 0; i < 6; i++)
    60         printf("%d ",a[i]);
    61     return 0;
    62 } 
    归并排序 - 递归实现

    非递归算法

     用循环

     O(N)

     稳定

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 typedef int ElementType;
     4 
     5 /* 归并排序 - 循环实现 */
     6 
     7 /* L = 左边起始位置, R = 右边起始位置, RightEnd = 右边终点位置*/
     8 void Merge( ElementType A[], ElementType TmpA[], int L, int R, int RightEnd )
     9 { /* 将有序的A[L]~A[R-1]和A[R]~A[RightEnd]归并成一个有序序列 */
    10 
    11      int LeftEnd = R - 1; /* 左边终点位置 */
    12      int temp = L;         /* 有序序列的起始位置 */
    13      int NumElements = RightEnd - L + 1;
    14       
    15      while( L <= LeftEnd && R <= RightEnd ) {
    16          if ( A[L] <= A[R] )
    17              TmpA[temp++] = A[L++]; /* 将左边元素复制到TmpA */
    18          else
    19              TmpA[temp++] = A[R++]; /* 将右边元素复制到TmpA */
    20      }
    21  
    22      while( L <= LeftEnd )
    23          TmpA[temp++] = A[L++]; /* 直接复制左边剩下的 */
    24      while( R <= RightEnd )
    25          TmpA[temp++] = A[R++]; /* 直接复制右边剩下的 */
    26           
    27      for(int i = 0; i < NumElements; i++, RightEnd -- )
    28          A[RightEnd] = TmpA[RightEnd]; /* 将有序的TmpA[]复制回A[] */
    29 }
    30 
    31 /* length = 当前有序子列的长度*/
    32 void Merge_pass( ElementType A[], ElementType TmpA[], int N, int length )
    33 { /* 两两归并相邻有序子列 */
    34      int i, j;
    35        
    36      for ( i = 0; i <= N-2*length; i += 2*length )
    37          Merge( A, TmpA, i, i+length, i+2*length-1 );
    38      if ( i+length < N ) /* 归并最后2个子列*/
    39          Merge( A, TmpA, i, i+length, N-1);
    40      else /* 最后只剩1个子列*/
    41          for ( j = i; j < N; j++ ) TmpA[j] = A[j];
    42 }
    43  
    44 void Merge_Sort( ElementType A[], int N )
    45 { 
    46      int length; 
    47      ElementType *TmpA;
    48       
    49      length = 1; /* 初始化子序列长度*/
    50      TmpA = (ElementType *)malloc( N * sizeof( ElementType ) );
    51      if ( TmpA != NULL ) {
    52           while( length < N ) {
    53               Merge_pass( A, TmpA, N, length );
    54               length *= 2;
    55               Merge_pass( TmpA, A, N, length );
    56               length *= 2;
    57           }
    58           free( TmpA );
    59      }
    60      else printf( "空间不足" );
    61 }
    62 
    63 int main()
    64 {
    65     int a[] = {34,8,64,51,32,21};
    66     Merge_Sort(a,6);
    67     for(int i = 0; i < 6; i++)
    68         printf("%d ",a[i]);
    69     return 0;
    70 } 
    归并排序 - 循环实现
  • 相关阅读:
    Javascript 操作select控件大全(新增、修改、删除、选中、清空、判断存在等) 转载
    FCKeditor 2.6 + Asp.Net 设置
    19个常用.net webservice服务集合
    ASP.NET Session无法使用或易丢失
    javascript实现缩略图
    Asp.net Excel导入或导出
    smarty截取中文乱码问题解决办法转载
    Git学习
    Android活动(Activity)的基本介绍
    Android活动(Activity)Toast和Menu
  • 原文地址:https://www.cnblogs.com/kuotian/p/5458963.html
Copyright © 2011-2022 走看看