1 / 156

第七章 内排序

第七章 内排序. 大纲. 7.1 基本概念 7.2 三种O (n 2 ) 的简单排序 插入排序 直接插入排序 二分法插入排序 冒泡排序 选择排序 7.3 Shell 排序. 大纲(续). 7.4 基于分治法的排序 快速排序 归并排序 7.5 堆排序 7.6 分配排序和基数排序 7.7 各种排序算法的理论和实验时间代价 7.8 排序问题的下限. 7.1 基本概念. 记录 (Record) :结点,进行排序的基本单位 关键码 (Key) :唯一确定记录的一个或多个域 排序码 (Sort Key) : 作为排序运算依据的一个 或多个域

makaio
Download Presentation

第七章 内排序

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第七章 内排序

  2. 大纲 • 7.1 基本概念 • 7.2 三种O(n2)的简单排序 • 插入排序 • 直接插入排序 • 二分法插入排序 • 冒泡排序 • 选择排序 • 7.3 Shell排序

  3. 大纲(续) • 7.4 基于分治法的排序 • 快速排序 • 归并排序 • 7.5 堆排序 • 7.6 分配排序和基数排序 • 7.7 各种排序算法的理论和实验时间代价 • 7.8 排序问题的下限

  4. 7.1基本概念 • 记录(Record):结点,进行排序的基本单位 • 关键码(Key):唯一确定记录的一个或多个域 • 排序码(Sort Key):作为排序运算依据的一个 或多个域 • 序列(Sequence):线性表,由记录组成的集合

  5. 7.1基本概念(续) • 排序(Sorting)—将序列中的记录按照排序码特定的顺序排列起来,即排序码域的值具有不减(或不增)的顺序。

  6. 排序问题 • 给定一个序列R ={r1, r2, …,rn},其排序码分别为k ={k1, k2, …,kn} • 排序的目的就是将R中的记录按照特定的顺序重新排列,形成一个新的有序序列R’= {r’1, r’2, …,r’n} • 相应排序码为k’ ={k’1, k’2, …,k’n} • 其中k’1≤k’2≤…≤k’n或k’1≥k’2≥…≥k’n,前者称为不减序,后者称为不增序。

  7. 7.1基本概念(续) • 内排序(Internal Sorting):整个排序过程中所有的记录都可以直接存放在内存中 • 外排序(External Sorting):内存无法容纳所有记录,排序过程中还需要访问外存

  8. 7.1基本概念(续) • “正序”序列 :待排序序列正好符合排序要求 • “逆序” 序列 :把待排序序列逆转过来,正好符合排序要求

  9. 7.1基本概念(续) • “稳定的”(stable)排序算法 :如果存在多个具有相同排序码的记录,经过排序后这些记录的相对次序仍然保持不变 。

  10. 排序算法的分类 • 简单排序 • 插入排序(Insert sort) • 直接选择排序(Selection sort) • 冒泡排序(Bubble sort) • Shell排序(Shell sort)

  11. 排序算法的分类(续) • 分治排序 • 快速排序(Quicksort) • 归并排序(Mergesort) • 堆排序(Heapsort) • 分配排序 (Binsort)

  12. 排序算法的衡量标准 • 时间代价:记录的比较和交换次数 • 空间代价 • 算法的复杂度

  13. 总的排序类 template <class Record,class Compare> class Sorter{ //总排序类 protected: //交换数组中的两个元素 static void swap(Record Array[],int i,int j); public: //对数组Array进行排序 void Sort(Record Array[],int n); //输出数组内容 void PrintArray(Record array[], int n); };

  14. Compare类 • Compare类是用来比较记录的排序码,把它单独定义成模板参数,是为了方便针对不同类型的排序码进行比较。为了简便起见, 我们只讨论整数排序的例子。

  15. int_intCompare 类 class int_intCompare{ //比较两个整型记录大小 public: static bool lt(int x,int y) {return x<y;} static bool eq(int x,int y) {return x==y;} static bool gt(int x,int y) {return x>y;} static bool le(int x,int y) {return x<=y;} static bool ge(int x,int y) {return x>=y;} };

  16. swap函数 template <class Record,class Compare> void Sorter<Record,Compare>:: swap(Record Array[],int i,int j) { //交换数组中的两个元素 Record TempRecord = Array[i]; Array[i] = Array[j]; Array[j] = TempRecord; }

  17. PrintArray函数 template <class Record,class Compare> void Sorter<Record,Compare>:: PrintArray(Record Array[], int n) { //输出数组内容 for(int i=0;i<n;i++) cout<<Array[i]<<" "; cout<<endl; }

  18. 7.2 三种O(n2)的简单排序 • 插入排序(Insert Sort) • 冒泡排序(Bubble Sort) • 选择排序 (Selection Sort)

  19. 7.2.1插入排序 • 算法思想: • 逐个处理待排序的记录,每个新记录都要与前面那些已排好序的记录进行比较,然后插入到适当的位置。

  20. 插入排序类 template <class Record,class Compare> class InsertSorter:public Sorter<Record,Compare>{};

  21. 直接插入排序 template <class Record,class Compare> class StraightInsertSorter:public InsertSorter<Record,Compare> { //直接插入排序类 public: void Sort(Record Array[],int n); };

  22. template <class Record,class Compare> void StraightInsertSorter<Record,Compare>:: Sort(Record Array[], int n) { //Array[]为待排序数组,n为数组长度 for (int i=1; i<n; i++) // 依次插入第i个记录 { //依次与前面的记录进行比较,发现逆置就交换 for (int j=i;j>0;j--){ if (Compare::lt(Array[j], Array[j-1])) swap(Array, j, j-1); else break; //此时i前面记录已排序 } } }

  23. 算法分析 • 稳定 • 空间代价:Θ(1) • 时间代价: • 最佳情况:n-1次比较,0次比较,Θ(n) • 最差情况:比较和交换次数为 • 平均情况:Θ(n2)

  24. 优化的插入排序算法 template <class Record,class Compare> class ImprovedInsertSorter:public InsertSorter<Record,Compare> { //优化的插入排序类 public: void Sort(Record Array[],int n); };

  25. template <class Record,class Compare> void ImprovedInsertSorter<Record,Compare>:: Sort(Record Array[], int n) { //Array[]为待排序数组,n为数组长度 Record TempRecord; // 临时变量 // 依次插入第i个记录 for (int i=1; i<n; i++) { TempRecord=Array[i]; //从i开始往前寻找记录i的正确位置 int j = i-1;

  26. //将那些大于等于记录i的记录后移 while ((j>=0) && (Compare::lt(TempRecord, Array[j]))) { Array[j+1] = Array[j]; j = j - 1; } //此时j后面就是记录i的正确位置,回填 Array[j+1] = TempRecord; } }

  27. 二分法插入排序 • 算法思想: • 在插入第i个记录时,前面的记录已经是有序的了,可以用二分法查找第i个记录的正确位置 。

  28. template <class Record,class Compare> class BinaryInsertSorter:public InsertSorter<Record,Compare> { //二分法插入排序类 public: void Sort(Record Array[],int n); };

  29. template <class Record,class Compare> void BinaryInsertSorter<Record,Compare>:: Sort(Record Array[], int n) { //Array[]为待排序数组,n为数组长度 Record TempRecord; //临时变量 //记录已排好序序列的左、右、中位置 int left,right,middle; //依次插入第i个记录 for (int i=1;i<n;i++) { //保存当前待插入记录 TempRecord = Array[i];

  30. //记录已排好序序列的左右位置 left = 0; right = i-1; //开始查找待插入记录的正确位置 while(left <= right) { //中间位置 middle = (left+right)/2; //如果待插入记录比中间记录小, // 就在左一半中查找, // 否则在右一半中查找 if (Compare::lt(TempRecord,Array[mi ddle])) right = middle-1;

  31. else left = middle+1; } //将前面所有大于当前待插入记录的记录后移 for(int j = i-1; j >= left; j --) Array[j+1] = Array[j]; //将待插入记录回填到正确位置 Array[left] = TempRecord; } }

  32. 算法分析 • 稳定 • 空间代价:Θ(1) • 时间代价: • 插入每个记录需要Θ(log i)次比较 • 最多移动i+1次 ,最少2次(移动临时记录) • 因此最佳情况下总时间代价为 Θ(nlog n) ,最差和平均情况下仍为Θ(n2)

  33. 7.2.2 冒泡排序 • 算法思想: • 不停地比较相邻的记录,如果不满足排序要求,就交换相邻记录,直到所有的记录都已经排好序。

  34. 冒泡排序类 template <class Record,class Compare> class BubbleSorter:public Sorter<Record,Compare> { //冒泡排序类 public: void Sort(Record Array[],int n); };

  35. 冒泡排序算法 template <class Record,class Compare> void BubbleSorter<Record,Compare>:: Sort(Record Array[], int n) { //冒泡排序,Array[]为待排数组,n为数组长度 //第i个记录冒泡 for (int i=1; i<n; i++) //依次比较相邻记录,如果发现逆置,就交换 for (int j=n-1; j>=i; j--) if (Compare::lt(Array[j], Array[j-1])) swap(Array, j, j-1); }

  36. 算法分析 • 稳定 • 空间代价:Θ(1) • 时间代价 : • 比较次数 : • 交换次数最多为Θ(n2),最少为0,平均为Θ(n2)。 • 最大,最小,平均时间代价均为Θ(n2)。

  37. 优化的冒泡排序 • 改进:检查每次冒泡过程中是否发生过交换,如果没有,则表明整个数组已经排好序了,排序结束。 • 避免不必要的比较

  38. 优化的冒泡排序 template <class Record,class Compare> class ImprovedBubbleSorter:public Sorter<Record,Compare> { //优化的冒泡排序类 public: void Sort(Record Array[],int n); };

  39. template <class Record,class Compare> void ImprovedBubbleSorter<Record,Compare>:: Sort(Record Array[], int n) { //Array[]为待排序数组,n为数组长度 bool NoSwap; // 是否发生交换的标志 for (int i=1; i<n; i++) { NoSwap = true; // 标志初始为真 for (int j=n-1; j>=i; j--)

  40. if (Compare::lt(Array[j], Array[j-1])) { //如果发生了交换, //标志变为假 swap(Array, j, j-1); NoSwap = false; } // 如果没发生过交换, // 表示已排好序,结束算法 if (NoSwap) return; } }

  41. 算法分析 • 稳定 • 空间代价为Θ(1) • 时间代价: • 最小时间代价为Θ(n):最佳情况下只运行第一轮循环 • 其他情况下时间代价仍为Θ(n2)

  42. 7.2.3 直接选择排序 • 算法思想: • 找出剩下的未排序记录中的最小记录,然后直接与数组中第i个记录交换 ,比冒泡排序减少了移动次数

  43. 直接选择排序 template <class Record,class Compare> class StraightSelectSorter:public Sorter<Record,Compare> { //直接选择排序类 public: void Sort(Record Array[],int n); };

  44. template <class Record,class Compare> void StraightSelectSorter<Record,Compare>:: Sort(Record Array[], int n) { //Array[]为待排序数组,n为数组长度 // 依次选出第i小的记录, // 即剩余记录中最小的那个 for (int i=0; i<n-1; i++) { // 首先假设记录i就是最小的 int Smallest = i; // 开始向后扫描所有剩余记录 for (int j=i+1;j<n; j++)

  45. // 如果发现更小的记录,记录它的位置 if (Compare::lt(Array[j], Array[Smallest])) Smallest = j; //将第i小的记录放在数组中第i个位置 swap(Array, i, Smallest); } }

  46. 算法分析 • 不稳定 • 空间代价:Θ(1) • 时间代价 : • 比较次数:Θ(n2),与冒泡排序一样 • 交换次数:n-1 • 总时间代价:Θ(n2)

  47. 7.2.4 简单排序算法的时间代价对比

More Related