`
zwt2001267
  • 浏览: 446820 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

数据结构中的各种排序---总结篇

 
阅读更多

转发:http://blog.csdn.net/wzyhb123456789/article/details/5974790

 

一、基本概念:

1、  排序:按照一定的关键字,将一个序列排列成想要得到的一个新的序列。

2、  内部排序和外部排序:整个排序过程完全在内存中进行,叫做内部排序。数据量较大需要借助外部存储设备才能完成,叫做外部排序。

3、  主关键字和此关键字:

4、  排序的稳定性:对于相同的元素来说,在排序之前和之后的书讯是一样的,那么这种排序就是稳定的排序,如果顺序发生了变化,那么就是不稳定排序。

二、插入类排序:

(一)   思想:在一个已经排好序的序列中,将未被排进的元素按照原先的规定插入到指定位置。

(二)   分类:

1、  直接插入排序:

①   思想:最基本的插入排序,将第i个插入到前i-1个中的适当位置。

②   时间复杂度:T(n) = O(n²)

③   空间复杂度:S(n) = O(1)

④   稳定性:稳定排序。循环条件while(r[0].key < r[j].key)保证的。

⑤   程序:

 

[cpp] view plaincopy
 
  1. void InsSort(RecordType r[], int length)  
  2. {  
  3.     for(i = 2; I <= length; i++)  
  4.     {  
  5.         r[0] = r[i];  
  6.         j = i – 1;  
  7.         while(r[0].key < r[j].key)  
  8.         {  
  9.             r[j + 1] = r[j]; j = j – 1;  
  10.         }  
  11.         r[j+1] = r[0];  
  12.     }  
  13. }  

 

2、  折半插入排序:

①   思想:因为是已经确定了前部分是有序序列,所以在查找插入位置的时候可以用折半查找的方法进行查找,提高效率。

②   时间复杂度:比较时的时间减为O(nn),但是移动元素的时间耗费未变,所以总是得时间复杂度还是O(n²)

③   空间复杂度:S(n) = O(1)

④   稳定性:稳定排序。

⑤   程序:

 

[cpp] view plaincopy
 
  1. void BinSort(RecordType r[], int length)  
  2. {  
  3.     for(i = 2; i <= length; i++)  
  4.     {  
  5.         x = r[i];  
  6.         low = 1; high = i – 1;  
  7.         while(low <= high)  
  8.         {  
  9.             mid = (low + high) / 2;  
  10.             if(x.key < r[mid].key)  
  11.                 high = mid – 1;  
  12.             else  
  13.                 low = mid – 1;  
  14.         }  
  15.         for(j = i – 1; j >= low; --j)  
  16.             r[j + 1] = r[j];  
  17.         r[low] = x;  
  18.     }  
  19. }  

 

3、  希尔排序:

①   思想:又称缩小增量排序法。把待排序序列分成若干较小的子序列,然后逐个使用直接插入排序法排序,最后再对一个较为有序的序列进行一次排序,主要是为了减少移动的次数,提高效率。原理应该就是从无序到渐渐有序,要比直接从无序到有序移动的次数会少一些。

②   时间复杂度:O(n1.5次方)

③   空间复杂度:O(1)

④   稳定性:不稳定排序。{2,4,1,2}21一组42一组,进行希尔排序,第一个2和最后一个2会发生位置上的变化。

⑤   程序:

 

[cpp] view plaincopy
 
  1. void ShellInsert(RecordType r[], int length, int delta)  
  2. {  
  3.     for(i = 1 + delta; i <= length; i++)/*1+delta为第一个子序列的第二个元素的下表*/  
  4.     if(r[i].key < r[1 - delta].key)  
  5.     {  
  6.         r[0] = r[i];  
  7.         for(j = i – delta; j > 0 && r[0].key < r[j].key; j -=delta)  
  8.             r[j + delta] = r[j];  
  9.         r[j + delta] = r[0];  
  10.     }  
  11. }  
  12. void ShellSort(RecordType r[], int length, int delta[], int n)  
  13. {  
  14.     for(i = 0; i <= n – 1; ++i)  
  15.         ShellInsert(r, length, delta[i]);  
  16. }  

 

三、交换类排序:

(一)   思想:通过交换逆序元素进行排序的方法。

(二)   分类:

1、  冒泡排序:

①   思想:反复扫描待排序序列,在扫描的过程中顺次比较相邻的两个元素的大小,若逆序就交换位置。第一趟,从第一个数据开始,比较相邻的两个数据,(以升序为例)如果大就交换,得到一个最大数据在末尾;然后进行第二趟,只扫描前n-1个元素,得到次大的放在倒数第二位。以此类推,最后得到升序序列。如果在扫描过程中,发现没有交换,说明已经排好序列,直接终止扫描。所以最多进行n-1趟扫描。

②   时间复杂度:T(n) = O(n²)

③   空间复杂度:S(n) = O(1)

④   稳定性:稳定排序。

⑤   程序:

 

[cpp] view plaincopy
 
  1. void BubbleSort(RecordType r[], int length)  
  2. {  
  3.     n = length;  
  4.     change = TRUE;  
  5.     for(i = 1; i <= n – 1 && change; i++)  
  6.     {  
  7.         change = FALSE;  
  8.         for(j = 1; j <= n – I; ++j)  
  9.             if(r[j].key > r[j + 1].key)  
  10.             {  
  11.                 x = r[j];  
  12.                 r[j] = r[j + 1];  
  13.                 r[j + 1] = x;  
  14.                 change = TRUE;  
  15.              }  
  16.     }  
  17. }  

 

2、  快速排序:

①   思想:冒泡排序一次只能消除一个逆序,为了能一次消除多个逆序,采用快速排序。以一个关键字为轴,从左从右依次与其进行对比,然后交换,第一趟结束后,可以把序列分为两个子序列,然后再分段进行快速排序,达到高效。

②   时间复杂度:平均T(n) = O(nn),最坏O(n²)

③   空间复杂度:S(n) = O(n)

④   稳定性:不稳定排序。{3 2 2}

⑤   程序:

 

[cpp] view plaincopy
 
  1. void QKSort(RecordType r[], int low, int high)  
  2. {  
  3.     int pos;  
  4.     if(low < high)  
  5.     {  
  6.         pos = QKPass(r, low, high);  
  7.         QKSort(r, low, pos - 1);  
  8.         QKSort(r, pos + 1, high);  
  9.     }  
  10. }  
  11. int QKPass(RecordType r[], int left, int right)  
  12. {  
  13.     RecordType x;  
  14.     int low, high;  
  15.     x = r[left];  
  16.     low = left;  
  17.     high = right;  
  18.     while(low < high)  
  19.     {  
  20.         while(low < high && r[high].key >= x.key)  
  21.             high--;  
  22.         if(low < high)  
  23.         {  
  24.             r[low] = r[high];  
  25.             low++;  
  26.         }  
  27.         while(low < high && r[low].key < x.key)  
  28.             low++;  
  29.         if(low < high)  
  30.         {  
  31.             r[high] = r[low];  
  32.             high--;  
  33.         }  
  34.     }  
  35.     r[low] = x;  
  36.     return low;  
  37. }  

 

四、选择类排序:

(一)   思想:每一趟在n – i + 1 ( i = 1,2,  , n - 1)个记录中选取关键字最小的记录作为有序序列中的第i个记录。

(二)   分类:

1、  简单选择排序:

①   思想:第一趟时,从第一个记录开始,通过n – 1次关键字的比较,从n个记录中选出关键字最小的记录,并和第一个记录进行交换。第二趟从第二个记录开始,选择最小的和第二个记录交换。以此类推,直至全部排序完毕。

②   时间复杂度:T(n) = O(n²)

③   空间复杂度:S(n) = O(1)

④   稳定性:不稳定排序,{3 3 2}

⑤   程序:

 

[cpp] view plaincopy
 
  1. void SelectSort(RecordType r[], int length)  
  2. {  
  3.     n = length;  
  4.     for(i = 1; i <= n - 1; i++)  
  5.     {  
  6.         k = i;  
  7.         for(j = i + 1; j <= n; i++)  
  8.         if(r[j].key < r[k],key)  
  9.             k = j;  
  10.             if(k != i)  
  11.             {  
  12.                 x = r[i];  
  13.                 r[i] = r[k];  
  14.                 r[k] = x;  
  15.             }  
  16.     }  
  17. }  

 

2、  树形选择排序:

①   思想:为了减少比较次数,两两进行比较,得出的较小的值再两两比较,直至得出最小的输出,然后在原来位置上置为∞,再进行比较。直至所有都输出。

②   时间复杂度:T(n) = O(nn)

③   空间复杂度:较简单选择排序,增加了n-1个额外的存储空间存放中间比较结果,就是树形结构的所有根节点。S(n) = O(n)

④   稳定性:稳定排序。

⑤   程序:

3、  堆排序:

①   思想:把待排序记录的关键字存放在数组r[1…n]中,将r看成是一刻完全二叉树的顺序表示,每个节点表示一个记录,第一个记录r[1]作为二叉树的根,一下个记录r[2…n]依次逐层从左到右顺序排列,任意节点r[i]的左孩子是r[2i],右孩子是r[2i+1],双亲是r[i/2向下取整]。然后对这棵完全二叉树进行调整建堆。

②   时间复杂度:T(n) = O(nn)

③   空间复杂度:S(n) = O(1)

④   稳定性:不稳定排序。{5 5 3}

⑤   程序:

(1)     调整堆:

 

[cpp] view plaincopy
 
  1. void sift(RecordType r[], int k, int m)  
  2. {  
  3.     /*假设r[k...m]是以r[k]为根的完全二叉树,而且分别以r[2k]和r[2k+1]为根的左右子树为大根堆,调整r[k],使整个序列r[k...m]满足堆的性质*/  
  4.     t = r[k];/*暂存“根”记录r[k]*/  
  5.     x = r[k].key;  
  6.     i = k;  
  7.     j = 2 * i;  
  8.     finished = FALSE;  
  9.     while(j <= m && !finished)  
  10.     {  
  11.         if(j < m && r[j].key < r[j + 1].key)  
  12.             j = j + 1;/*若存在右子树,且右子树根的关键字大,则沿右分支“筛选”*/  
  13.         if(x >= r[j].key)  
  14.             finished = TRUE;/*筛选完毕*/  
  15.         else  
  16.         {  
  17.             r[i] = r[j];  
  18.             i = j;  
  19.             j = 2 * i;  
  20.         }/*继续筛选*/  
  21.     }  
  22.     r[i] = t;/*将r[k]填入到恰当的位置*/  
  23. }  

 

(2)     建初堆:

 

[cpp] view plaincopy
 
  1. void crt_heap(recordType r[], int length)  
  2. {  
  3.     n = length;  
  4.     for(i = n / 2; i >= 1; --i)/*自第n/2向下取整 个记录开始进行筛选建堆*/  
  5.         sift(r, i, n);  
  6. }  

 

(3)     堆排序:

 

[cpp] view plaincopy
 
  1. void HeapSort(RecordType r[], int length)  
  2. {  
  3.     crt_heap(r, length);  
  4.     n = length;  
  5.     for(i = n; i >= 2; --i)  
  6.     {  
  7.         b = r[1];/*将堆顶记录和堆中的最后一个记录互换*/  
  8.         r[1] = r[i];  
  9.         r[i] = b;  
  10.         sift(r, 1, i - 1);/*进行调整,使r[1…i-1]变成堆*/  
  11.     }  
  12. }  

 

五、归并排序:

(一)   思想:

(二)   分类:

1、  归并排序:

①   思想:假设初始序列右n个记录,首先将这n个记录看成n个有序的子序列,每个子序列的长度为1,然后两两归并,得到n/2向上取整 个长度为2n为奇数时,最后一个序列的长度为1)的有序子序列。在此基础上,在对长度为2的有序子序列进行两两归并,得到若干个长度为4的有序子序列。如此重复,直至得到一个长度为n的有序序列为止。

②   时间复杂度:T(n) = O(nn)

③   空间复杂度:S(n) = O(n)

④   稳定性:稳定排序。

⑤   程序:

 

[cpp] view plaincopy
 
  1. void Merge(RecordType r1[], int low, int mid, int high, RecordType r2[])  
  2. {  
  3.     /*已知r1[low...mid]和r1[mid + 1...high]分别按关键字有序排列,将它们合并成一个有序序列,存放在r2[low...high]*/  
  4.     i = low;  
  5.     j = mid + 1;  
  6.     k = low;  
  7.     while((i <= mid) && (j <= high))  
  8.     {  
  9.         if(r1[i].key <= r1[j].key)  
  10.         {  
  11.             r2[k] = r1[i];  
  12.             ++i;  
  13.         }  
  14.         else  
  15.         {  
  16.             r2[k] = r1[j];  
  17.             ++j;  
  18.         }  
  19.         ++k;  
  20.     }  
  21.     while(i <= mid)  
  22.     {  
  23.         r2[k] = r1[i];  
  24.         k++;  
  25.         i++;  
  26.     }  
  27.     while(j <= high)  
  28.     {  
  29.         r2[k] = r1[j];  
  30.         k++;  
  31.         j++;  
  32.     }  
  33. }  
  34. void MSort(RecordType r1[], int low, int high, RecordType r3[])  
  35. {  
  36.     /*r1[low...high]经过排序后放在r3[low...high]中,r2[low...high]为辅助空间*/  
  37.     RecordType r2[N];  
  38.     if(low == high)  
  39.     r3[low] = r1[low];  
  40.     else  
  41.     {  
  42.         mid = (low + high) / 2;  
  43.         MSort(r1, low, mid, r2);  
  44.         MSort(r1, mid + 1, high, r2);  
  45.         Merge(r2, low, mid, high, r3);  
  46.     }  
  47. }  
  48. void MergeSort(RecordType r[], int n)  
  49. {  
  50.     /*对记录数组r[1...n]做归并排序*/  
  51.     MSort(r, 1, n, r);  
  52. }  

 

六、分配类排序:

(一)   思想:分配类排序是利用分配和收集两种基本操作。

(二)   分类:

1、  多关键字排序:

2、  链式基数排序:

①   思想:先分配,再收集,就是先按照一个次关键字收集一下,然后进行收集(第一个排序),然后再换一个关键字把新序列分配一下,然后再收集起来,又完成一次排序,这样所有关键字分配收集完后,就完成了排序。

②   时间复杂度:T(n) = O( d ( n + rd ) )

③   空间复杂度:S(n) = O(rd)

④   稳定性:稳定排序。

⑤   程序:

七、总结:

(1)简单排序法一般只用于n较小的情况(例如n<30)。当序列的记录“基本有序”时,直接插入排序是最佳的排序方法。如果记录中的数据较多,则应采用移动次数较少的简单选择排序法。

(2)快速排序、堆排序和归并排序的平均时间复杂度均为O(nn),但实验结果表明,就平均时间性能而言,快速排序是所有排序方法中最好的。遗憾的是,快速排序在最坏情况下的时间性能为O(n²)。堆排序和归并排序的最坏时间复杂度仍为O(nn),当n较大时,归并排序的时间性能优于堆排序,但它所需的辅助空间最多。

(3)可以将简单排序法与性能较好的排序方法结合使用。例如,在快速排序中,当划分子区间的长度小于某值时,可以转而调用直接插入排序法;或者先将待排序序列划分成若干子序列,分别进行直接插入排序,然后再利用归并排序法,将有序子序列合并成一个完整的有序序列。

(4)基数排序的时间复杂度可以写成O(d·n)。因此,它最适合于n值很大而关键字的位数d较小的序列。当d远小于n时,其时间复杂度接近O(n)

(5)从排序的稳定性上来看,在所有简单排序法中,简单选择排序是不稳定的,其他各种简单排序法都是稳定的。然而,在那些时间性能较好的排序方法中,希尔排序、快速排序、堆排序都是不稳定的,只有归并排序、基数排序是稳定的。

分享到:
评论

相关推荐

    数据结构 各种排序所需时间的比较

    在计算机科学领域,排序是处理数据的一个重要环节,特别是在数据结构和算法中。各种排序算法在不同的场景下有着各自的优势,而它们的时间复杂度则直接决定了算法的效率。本篇文章将详细探讨Vc++环境下几种常见排序...

    数据结构各种内排序性能比较课程设计报告

    这篇“数据结构各种内排序性能比较课程设计报告”旨在通过对比多种排序算法,了解它们的性能差异,以便在实际应用中选择最适合的方法。以下是几种排序算法的详细说明: 1. **冒泡排序**(Bubble Sort): 冒泡排序...

    数据结构实验报告 排序

    这篇数据结构实验报告主要关注的是排序算法的实现和比较,特别是在链表数据结构上的应用。实验涉及了五种常见的排序算法:插入排序、冒泡排序、快速排序、简单选择排序,以及可能包括的其他排序算法。以下是这些算法...

    数据结构实验中所有排序算法

    本篇将深入探讨数据结构实验中常见的几种排序算法,包括插入排序、冒泡排序、选择排序以及快速排序,通过分析它们的工作原理、时间复杂度以及应用场景,帮助读者全面理解这些算法。 ### 一、插入排序(Insertion ...

    数据结构排序总结及java实现

    ### 数据结构排序总结及Java实现 #### 排序概述 排序是计算机科学中一项重要的基础技术,用于将一组数据按照特定顺序(升序或降序)进行排列。本篇文章将介绍几种常见的排序算法,并提供相应的Java实现代码。这些...

    数据结构 直接插入排序

    ### 数据结构之直接插入排序详解 #### 一、引言 在计算机科学中,排序算法是数据处理中不可或缺的一部分,而直接插入排序是一种简单直观的排序方法。它的工作原理类似于我们手动排序一组卡片的方式——每次从未...

    c++数据结构--冒泡排序

    ### C++ 数据结构 -- 冒泡排序 #### 知识点概述 本篇文章将深入探讨在C++环境下如何实现冒泡排序算法,并解释为何在某些情况下返回局部变量的地址会导致程序出错。此外,我们还将分析如何正确地利用全局变量或引用...

    数据结构排序以及排序的技巧

    总结,数据结构中的排序方法多种多样,每种都有其适用场景和特性。理解这些方法的稳定性和效率可以帮助我们根据具体需求选择最佳的排序算法。在实际应用中,结合数据特性和算法性能进行合理选择,是提高程序效率的...

    汽车牌照的排序与查找问题-数据结构与算法课程设计报告.pdf

    总结来说,本报告所提出的基于数据结构与算法的车牌排序与查找方案,不仅提高了处理效率,也展示了计算机技术在实际应用中的强大能力。通过链表、基数排序、二分查找等方法的综合运用,成功构建了一个高效、实用的...

    数据结构课程设计——各种排序

    在数据结构课程设计中,排序是一个非常关键的话题,因为排序算法在实际应用中无处不在,如数据库查询、数据分析等。本篇文章将深入探讨五种基本的排序算法:直接插入排序、快速排序、堆排序、冒泡排序以及希尔排序。...

    数据结构排序详细解说(1)

    排序是数据结构和算法的重要组成部分,无论是插入排序还是交换排序,都有其适用的场景和优缺点。理解排序的基本概念和不同排序算法的工作原理,可以帮助我们在实际编程中选择最适合的排序方法,从而提高程序的效率和...

    S7-200SMART冒泡排序-优化版(可选择升序降序及数据类型等).zip

    总结来说,S7-200SMART PLC实现冒泡排序优化版的关键在于利用ST语言的强大功能,结合条件判断和数据类型的动态处理,实现排序方式和数据类型的多样化。通过这种方式,我们可以创建出既高效又灵活的PLC排序程序,服务...

    数据结构课程设计 排序综合

    通过这篇课程设计,我们可以了解到数据结构中排序的重要性和各种排序算法的实现。下面是这个课程设计的知识点总结: 1. 排序的重要性:排序是数据处理中的一种重要方法之一,对于大量数据的处理已经成为一个非常...

    数据结构排序方法总结.docx

    总结来说,数据结构中的插入类排序方法提供了基础的排序思路,它们在实际应用中有着广泛的应用,尤其是在数据量较小或者部分有序的情况下,直接插入排序和希尔排序都能展现出良好的性能。理解这些排序方法的基本思想...

    数据结构---线性表之单链表(C语言)

    单链表是数据结构中的一...总结,单链表是数据结构中的基本单元,理解和掌握它的操作是编程基础的重要组成部分。通过C语言实现,我们可以直观地理解链表的工作原理,这对于进一步学习高级数据结构和算法具有重要意义。

    数据结构排序方法总结.pdf

    本篇总结将重点关注两种在数据结构排序中极为常见的方法:插入类排序和希尔排序。 插入类排序是一类基于比较的排序算法,其核心思路是将无序的记录序列通过比较与移动,逐渐插入到已排序的序列中,直至整个序列达到...

    数据结构中经典排序算法

    ### 数据结构中经典排序算法详解 #### 一、概述 排序是计算机科学中的一项基本操作,用于将数据按特定顺序排列。排序算法的选择通常取决于数据的特性以及应用场景的需求。本篇文章将详细介绍几种经典的排序算法及其...

    数据结构各种排序方法的综合比较.pdf

    数据结构中的排序方法是计算机科学中的重要主题,用于组织和整理数据,以便高效地访问和检索。本篇文章将综合比较几种常见的排序算法,包括它们的时间性能、空间性能以及稳定性。 一、时间性能 1. **O(nlogn)**: ...

    数据结构作业:第10章排序题目.docx

    排序算法是数据结构中的一个基本概念,广泛应用于各种数据处理和分析领域。本篇作业总结了第10章排序题目,涵盖了直接插入排序、选择排序、冒泡排序、堆排序、快速排序、归并排序等多种排序算法。 1. 排序算法的...

Global site tag (gtag.js) - Google Analytics