• 各种排序


    数据结构排序算法总结

    这章的内容比较经典,都是一些很好的算法,将来很可能会用得到,总结一下,加深一下印象。

    文章篇幅有点大。

                   一:插入排序       1)直接插入排序          2)折半插入排序      3)希尔排序

                   二、交换排序      1)冒泡排序          2)快速排序     

                   三、选择排序      1)简单选择排序      2)堆排序     

                   四、归并排序     

                   五、基数排序    

            一、插入排序

                  1)直接插入排序    

                  时间复杂度:平均情况—O(n2)     最坏情况—O(n2)     辅助空间:O(1)      稳定性:稳定

    C 代码:

     1     void InsertSort(SqList &L) {      
     2     // 对顺序表L作直接插入排序。    
     3     int i,j;    
     4     for (i=2; i<=L.length; ++i)    
     5     if (LT(L.r[i].key, L.r[i-1].key)) {    
     6     // "<"时,需将L.r[i]插入有序子表    
     7     L.r[0] = L.r[i];                 // 复制为哨兵    
     8     for (j=i-1;   LT(L.r[0].key, L.r[j].key);   --j)    
     9     L.r[j+1] = L.r[j];             // 记录后移    
    10     L.r[j+1] = L.r[0];               // 插入到正确位置    
    11     }    
    12     } // InsertSort    

                  2)折半插入排序

                   时间复杂度:平均情况—O(n2)     稳定性:稳定

    C 代码

     1     void BInsertSort(SqList &L) {      
     2     // 对顺序表L作折半插入排序。    
     3     int i,j,high,low,m;    
     4     for (i=2; i<=L.length; ++i) {    
     5     L.r[0] = L.r[i];       // 将L.r[i]暂存到L.r[0]    
     6     low = 1;    high = i-1;    
     7     while (low<=high) {    // 在r[low..high]中折半查找有序插入的位置    
     8     m = (low+high)/2;                            // 折半    
     9     if (LT(L.r[0].key, L.r[m].key)) high = m-1;  // 插入点在低半区    
    10     else   low = m+1;                             // 插入点在高半区    
    11     }    
    12     for (j=i-1; j>=high+1; --j) L.r[j+1] = L.r[j];  // 记录后移    
    13     L.r[high+1] = L.r[0];                           // 插入    
    14     }    
    15     } // BInsertSort    

                  3)希尔排序 

                   时间复杂度:理想情况—O(nlog2n)      最坏情况—O(n2)     稳定性:不稳定

    C 代码实现:
    
    
     1     void ShellInsert(SqList &L, int dk) {      
     2     // 对顺序表L作一趟希尔插入排序。本算法对算法10.1作了以下修改:    
     3     //      1. 前后记录位置的增量是dk,而不是1;    
     4     //      2. r[0]只是暂存单元,不是哨兵。当j<=0时,插入位置已找到。    
     5     int i,j;    
     6     for (i=dk+1; i<=L.length; ++i)    
     7     if (LT(L.r[i].key, L.r[i-dk].key)) { // 需将L.r[i]插入有序增量子表    
     8     L.r[0] = L.r[i];                   // 暂存在L.r[0]    
     9     for (j=i-dk; j>0 && LT(L.r[0].key, L.r[j].key); j-=dk)    
    10     L.r[j+dk] = L.r[j];              // 记录后移,查找插入位置    
    11     L.r[j+dk] = L.r[0];                // 插入    
    12     }    
    13     } // ShellInsert    
    14     void ShellSort(SqList &L, int dlta[], int t) {   
    15     // 按增量序列dlta[0..t-1]对顺序表L作希尔排序。    
    16     for (int k=0; k<t; ++k)    
    17     ShellInsert(L, dlta[k]);  // 一趟增量为dlta[k]的插入排序    
    18     } // ShellSort    
    
    

            二、交换排序

                  1)冒泡排序 

                  时间复杂度:平均情况—O(n2)     最坏情况—O(n2)     辅助空间:O(1)      稳定性:稳定

    C 代码:

     1     void BubbleSort(SeqList R) {    
     2     int i,j;    
     3     Boolean exchange; //交换标志    
     4     for(i=1;i<n;i++){ //最多做n-1趟排序    
     5           exchange=FALSE; //本趟排序开始前,交换标志应为假    
     6          for(j=n-1;j>=i;j--) //对当前无序区R[i..n]自下向上扫描    
     7               if(R[j+1].key<R[j].key){//交换记录    
     8                    R[0]=R[j+1]; //R[0]不是哨兵,仅做暂存单元    
     9                    R[j+1]=R[j];    
    10       R[j]=R[0];    
    11                    exchange=TRUE; //发生了交换,故将交换标志置为真    
    12                }    
    13               if(!exchange) //本趟排序未发生交换,提前终止算法    
    14               return;    
    15     } //endfor(外循环)    
    16     } //BubbleSort    

                  2)快速排序 

                   时间复杂度:平均情况—O(nlog2n)     最坏情况—O(n2)     辅助空间:O(log2n)      稳定性:不稳定

    C 代码

     1     int Partition(SqList &L, int low, int high) {      
     2     // 交换顺序表L中子序列L.r[low..high]的记录,使枢轴记录到位,        
     3     // 并返回其所在位置,此时,在它之前(后)的记录均不大(小)于它        
     4     KeyType pivotkey;        
     5     RedType temp;        
     6     pivotkey = L.r[low].key;     // 用子表的第一个记录作枢轴记录        
     7     while (low<high) {           // 从表的两端交替地向中间扫描        
     8     while (low<high && L.r[high].key>=pivotkey) --high;        
     9     temp=L.r[low];        
    10     L.r[low]=L.r[high];        
    11     L.r[high]=temp;           // 将比枢轴记录小的记录交换到低端        
    12     while (low<high && L.r[low].key<=pivotkey) ++low;        
    13     temp=L.r[low];        
    14     L.r[low]=L.r[high];        
    15     L.r[high]=temp;           // 将比枢轴记录大的记录交换到高端        
    16     }        
    17     return low;                  // 返回枢轴所在位置        
    18     } // Partition        
    19     int Partition(SqList &L, int low, int high) {       
    20     // 交换顺序表L中子序列L.r[low..high]的记录,使枢轴记录到位,        
    21     // 并返回其所在位置,此时,在它之前(后)的记录均不大(小)于它        
    22     KeyType pivotkey;        
    23     L.r[0] = L.r[low];            // 用子表的第一个记录作枢轴记录        
    24     pivotkey = L.r[low].key;      // 枢轴记录关键字        
    25     while (low<high) {            // 从表的两端交替地向中间扫描        
    26     while (low<high && L.r[high].key>=pivotkey) --high;        
    27     L.r[low] = L.r[high];      // 将比枢轴记录小的记录移到低端        
    28     while (low<high && L.r[low].key<=pivotkey) ++low;        
    29     L.r[high] = L.r[low];      // 将比枢轴记录大的记录移到高端        
    30     }        
    31     L.r[low] = L.r[0];            // 枢轴记录到位        
    32     return low;                   // 返回枢轴位置        
    33     } // Partition        
    34     void QSort(SqList &L, int low, int high) {          
    35     // 对顺序表L中的子序列L.r[low..high]进行快速排序        
    36     int pivotloc;        
    37     if (low < high) {                      // 长度大于1        
    38     pivotloc = Partition(L, low, high);  // 将L.r[low..high]一分为二        
    39     QSort(L, low, pivotloc-1); // 对低子表递归排序,pivotloc是枢轴位置        
    40     QSort(L, pivotloc+1, high);          // 对高子表递归排序        
    41     }        
    42     } // QSort    
    43     void QuickSort(SqList &L) {  // 算法10.8    
    44     // 对顺序表L进行快速排序    
    45     QSort(L, 1, L.length);    
    46     } // QuickSort   

      三、选择排序 

                  1)简单选择排序 

                   时间复杂度:平均情况—O(n2)     最坏情况—O(n2)     辅助空间:O(1)      稳定性:不稳定

    C 代码:

     1 void SelectSort(SqList &L) {      
     2 // 对顺序表L作简单选择排序。    
     3 int i,j;    
     4 for (i=1; i<L.length; ++i) { // 选择第i小的记录,并交换到位    
     5 j = SelectMinKey(L, i);  // 在L.r[i..L.length]中选择key最小的记录    
     6 if (i!=j) {                // L.r[i]←→L.r[j];    与第i个记录交换    
     7 RedType temp;    
     8 temp=L.r[i];    
     9 L.r[i]=L.r[j];    
    10 L.r[j]=temp;        
    11 }    
    12 }    
    13 } // SelectSort   

                  2)堆排序 

                   时间复杂度:平均情况—O(nlog2n)     最坏情况—O(nlog2n)     辅助空间:O(1)      稳定性:不稳定

    C 代码

     1     void HeapAdjust(HeapType &H, int s, int m) {      
     2     // 已知H.r[s..m]中记录的关键字除H.r[s].key之外均满足堆的定义,    
     3     // 本函数调整H.r[s]的关键字,使H.r[s..m]成为一个大顶堆    
     4     // (对其中记录的关键字而言)    
     5     int j;    
     6     RedType rc;    
     7     rc = H.r[s];    
     8     for (j=2*s; j<=m; j*=2) {   // 沿key较大的孩子结点向下筛选    
     9     if (j<m && H.r[j].key<H.r[j+1].key) ++j; // j为key较大的记录的下标    
    10     if (rc.key >= H.r[j].key) break;         // rc应插入在位置s上    
    11     H.r[s] = H.r[j];   s = j;    
    12     }    
    13     H.r[s] = rc;  // 插入    
    14     } // HeapAdjust    
    15     void HeapSort(HeapType &H) {      
    16     // 对顺序表H进行堆排序。    
    17     int i;    
    18     RedType temp;    
    19     for (i=H.length/2; i>0; --i)  // 把H.r[1..H.length]建成大顶堆    
    20     HeapAdjust ( H, i, H.length );    
    21     for (i=H.length; i>1; --i) {    
    22     temp=H.r[i];    
    23     H.r[i]=H.r[1];    
    24     H.r[1]=temp;  // 将堆顶记录和当前未经排序子序列Hr[1..i]中    
    25     // 最后一个记录相互交换    
    26     HeapAdjust(H, 1, i-1);  // 将H.r[1..i-1] 重新调整为大顶堆    
    27     }    
    28     } // HeapSort    

            四、归并排序

                  1)归并排序 

                   时间复杂度:平均情况—O(nlog2n)      最坏情况—O(nlog2n)      辅助空间:O(n)      稳定性:稳定

    C 代码:

     1 void Merge (RedType SR[], RedType TR[], int i, int m, int n) {    
     2 // 将有序的SR[i..m]和SR[m+1..n]归并为有序的TR[i..n]    
     3 int j,k;    
     4 for (j=m+1, k=i;   i<=m && j<=n;   ++k) {       
     5 // 将SR中记录由小到大地并入TR    
     6 if LQ(SR[i].key,SR[j].key) TR[k] = SR[i++];    
     7 else TR[k] = SR[j++];    
     8 }    
     9 if (i<=m)  // TR[k..n] = SR[i..m];   将剩余的SR[i..m]复制到TR    
    10 while (k<=n && i<=m) TR[k++]=SR[i++];    
    11 if (j<=n)  // 将剩余的SR[j..n]复制到TR    
    12 while (k<=n &&j <=n) TR[k++]=SR[j++];    
    13 } // Merge    
    14 void MSort(RedType SR[], RedType TR1[], int s, int t) {    
    15 // 将SR[s..t]归并排序为TR1[s..t]。    
    16 int m;    
    17 RedType TR2[20];    
    18 if (s==t) TR1[t] = SR[s];    
    19 else {    
    20 m=(s+t)/2;            // 将SR[s..t]平分为SR[s..m]和SR[m+1..t]    
    21 MSort(SR,TR2,s,m);    // 递归地将SR[s..m]归并为有序的TR2[s..m]    
    22 MSort(SR,TR2,m+1,t);  // 将SR[m+1..t]归并为有序的TR2[m+1..t]    
    23 Merge(TR2,TR1,s,m,t); // 将TR2[s..m]和TR2[m+1..t]归并到TR1[s..t]    
    24 }    
    25 } // MSort    
    26 void MergeSort(SqList &L) {      
    27 // 对顺序表L作归并排序。    
    28 MSort(L.r, L.r, 1, L.length);    
    29 } // MergeSort   

            五、基数排序 

                  1)基数排序 

    时间复杂度:平均情况—O(d(n+rd))      最坏情况—O(d(n+rd))      辅助空间:O(rd)      稳定性:稳定

    C 代码:

     1     void Distribute(SLList &L, int i, ArrType &f, ArrType &e) {      
     2     // 静态链表L的r域中记录已按(keys[0],...,keys[i-1])有序,    
     3     // 本算法按第i个关键字keys[i]建立RADIX个子表,    
     4     // 使同一子表中记录的keys[i]相同。f[0..RADIX-1]和e[0..RADIX-1]    
     5     // 分别指向各子表中第一个和最后一个记录。    
     6     int j, p;    
     7     for (j=0; j<RADIX; ++j) f[j] = 0;     // 各子表初始化为空表    
     8     for (p=L.r[0].next;   p;   p=L.r[p].next) {    
     9     j = L.r[p].keys[i]-'0';  // 将记录中第i个关键字映射到[0..RADIX-1],    
    10     if (!f[j]) f[j] = p;    
    11     else L.r[e[j]].next = p;    
    12     e[j] = p;                // 将p所指的结点插入第j个子表中    
    13     }    
    14     } // Distribute    
    15     void Collect(SLList &L, int i, ArrType f, ArrType e) {      
    16     // 本算法按keys[i]自小至大地将f[0..RADIX-1]所指各子表依次链接成    
    17     // 一个链表,e[0..RADIX-1]为各子表的尾指针    
    18     int j,t;    
    19     for (j=0; !f[j]; j++);  // 找第一个非空子表,succ为求后继函数: ++    
    20     L.r[0].next = f[j];  // L.r[0].next指向第一个非空子表中第一个结点    
    21     t = e[j];    
    22     while (j<RADIX) {    
    23     for (j=j+1; j<RADIX && !f[j]; j++);       // 找下一个非空子表    
    24     if (j<RADIX) // 链接两个非空子表    
    25     { L.r[t].next = f[j];   t = e[j]; }    
    26     }    
    27     L.r[t].next = 0;   // t指向最后一个非空子表中的最后一个结点    
    28     } // Collect    
    29     void RadixSort(SLList &L) {      
    30     // L是采用静态链表表示的顺序表。    
    31     // 对L作基数排序,使得L成为按关键字自小到大的有序静态链表,    
    32     // L.r[0]为头结点。    
    33     int i;    
    34     ArrType f, e;    
    35     for (i=1; i<L.recnum; ++i) L.r[i-1].next = i;    
    36     L.r[L.recnum].next = 0;     // 将L改造为静态链表    
    37     for (i=0; i<L.keynum; ++i) {      
    38     // 按最低位优先依次对各关键字进行分配和收集    
    39     Distribute(L, i, f, e);    // 第i趟分配    
    40     Collect(L, i, f, e);       // 第i趟收集    
    41     print_SLList2(L, i);    
    42     }    
    43     } // RadixSort 
    这世界上有一种鸟是没有脚的,它只能够一直的飞呀飞呀,飞累了就在风里面睡觉,这种鸟一辈子只能下地一次,那一次就是它死亡的时候。
  • 相关阅读:
    2015.2.27 UltraEdit中显示XML结构
    2015.1.31 DataGridView自动滚动到某行
    2015.1.15 利用函数实现将一行记录拆分成多行记录 (多年想要的效果)
    2015.1.15 利用Oracle函数返回表结果 重大技术进步!
    2015.1.15 利用Oracle函数插入表结构 Bulk collect into 不用循环,简洁高效
    2015.1.8 Left join 左连接
    2015.1.10 解决DataGridView SelectionChanged事件自动触发问题
    delphi 遍历窗口
    delphi 访问 protected 属性 哈哈
    clientdataset 读取excel 如果excel 文件不存在的时候 相应的gird 会不显示数据, 鼠标掠过 gird 格子 才会显示数据。 这是一个bug 哈哈
  • 原文地址:https://www.cnblogs.com/xuyinghui/p/4593890.html
Copyright © 2020-2023  润新知