本章重点难点 重点:插入排序、快速排序、选择排序、归并排序、基数排序的思想和算法。

Slides:



Advertisements
Similar presentations
阻塞操作. 在 linux 里,一个等待队列由一个 wait_queue_head_t 类型的结构来描述 等待队列的初始化: static wait_queue_head_t testqueue; init_waitqueue_head(&testqueue);
Advertisements

回顾上节课的内容 二分 有序 堆 平方级排序算法简单介绍 交换排序 冒泡排序 插入排序 选择排序.
主讲:计算机工程学院 李兰 答疑地点:主教学楼B区213
数据结构及应用算法教程(修订版) 配套课件.
第十章 内部排序 知识点3:快速排序.
第十章 排序 排序定义——将一个数据元素(或记录)的任意序列,重新排列成一个按关键字有序的序列叫~ 排序分类 按待排序记录所在位置
第九章 排序 插入排序 交换排序 选择排序 归并排序 基数排序.
9.1 概述 9.2 插入排序 9.3 交换排序 9.4 选择排序 9.5 归并排序 9.6 基数排序 9.7 各种内部排序的比较
数据结构 第10章 内部排序.
常宝宝 北京大学计算机科学与技术系 数据结构(七) 常宝宝 北京大学计算机科学与技术系
C语言程序设计.
<<软件技术基础>>
第十章 内部排序 £10.1 概述 £10.5 归并排序 £10.2 插入排序 £10.6 基数排序 £10.3 快速排序
数据结构 第七章 排序.
第9章 内部排序 概述 插入排序 (直接插入、折半插入、表插入排序、希尔排序) 交换排序 (起泡排序、快速排序)
第八章 查找.
第十章 内部排序 10.1 概述 10.2 插入排序 直接插入排序 其他插入排序 希尔排序
第10章 排序.
第九章 排序 课前导学 9.1 排序的基本概念 9.2 插入类排序 9.3 交换类排序 9.4 选择类排序 9.5 归并排序
第8章 查找 数据结构(C++描述).
Chapter 7 Search.
第十章 内部排序.
第8章 排序.
10.1 概述 插入排序 快速排序 堆排序 归并排序 基数排序
10.1、基本概念 10.2、插入排序 10.3、快速排序 10.4、选择排序 10.5、归并排序 10.6、基数排序 10.7、讨论
第十章 排序.
第九章 排序 9.1排序的基本概念 9.2简单排序方法(复杂度 O(n2)) 9.3先进排序方法(复杂度 O(nLogn))
第十章 排序 10.1排序的基本概念 10.2简单排序方法(复杂度 O(n2))
第9章 排序.
第十章 内部排序.
第九章 排序 9.1排序的基本概念 9.2简单排序方法(复杂度 O(n2)) 9.3先进排序方法(复杂度 O(nLogn))
第2章 线性表 线性表抽象数据类型 顺序表 主要知识点 单链表 循环单链表 循环双向链表 静态链表 设计举例.
第2讲 绪论(二).
第9章 排序 9.1 排序的基本概念 9.2 插入排序 9.3 选择排序 9.4 交换排序 9.5 归并排序 9.6 基数排序.
本章重点难点 重点:顺序查找、二分查找、二叉排序树查找以及散列表查找的基本思想和算法实现。
第 3 讲 线性表(一).
中央广播电视大学开放教育试点课程 数据结构 辅导教师 倪政林.
第九章 排序 (Sort)
第9章 内部排序 9.1 概述 9.2 插入排序 9.3 快速排序 9.4 选择排序 9.5 归并排序 9.6 基数排序
第8章 排序 北京师范大学 教育技术学院 杨开城.
数据结构 本 章 说 明 10.1 概 述 10.2 插入排序 10.3 快速排序 10.4 堆 排 序 10.5 归并排序
数据结构 Data Structure CSU 主讲人:王国军,郑瑾 中南大学信息院计科系
第九章 查找 2019/2/16.
数据结构 第八章 查找.
第九章 排序 概述 插入排序 交换排序 选择排序 归并排序 *基数排序 *外排序.
顺序表的插入.
第十章内部排序 概述 插入排序 快速排序 选择排序 归并排序 基数排序.
教 师:曾晓东 电 话: E_mail: 计算机软件技术基础 教 师:曾晓东 电 话: E_mail:
计算机软件技术基础 数据结构与算法(5).
§ 堆排序(Floyd &Williams)
第8章 排序 本章中主要介绍下列内容: 插入排序 交换排序 选择排序 归并排序 基数排序.
顺序表的删除.
第九章 排序 概述 插入排序 快速排序 交换排序(起泡排序) 选择排序 归并排序.
9.1 基本概念 9.2 线性表的查找 9.3 树表的查找 9.4 哈希表的查找 9.5 各种查找方法的比较
第二章 Java基本语法 讲师:复凡.
顺序查找.
Ch.9 查找 §9.1 基本概念 查找和排序是两个重要的运算
3.16 枚举算法及其程序实现 ——数组的作用.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
10.3 (交换)快 速 排 序(知识点二) 一、起泡排序 二、一趟快速排序 三、快速排序 四、快速排序的时间分析.
第九章 排序 东南大学计算机学院 方效林 本课件借鉴了清华大学殷人昆老师 和哈尔滨工业大学张岩老师的课件.
排序查找 概述 插入排序 交换排序 选择排序 归并排序 主讲:朱佳 博士.
实验目的:掌握数据的顺序存储结构及它们在计算机中的操作。 实验内容:
第10章 排序 排序的基本概念 插入排序 选择排序 交换排序归并排序 基数排序 性能比较 主要知识点.
本节内容 动态链接库 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
主讲人: 吕敏 { } Spring 2012 ,USTC 算法基础 主讲人: 吕敏 { } Spring 2012 ,USTC.
插入排序的正确性证明 以及各种改进方法.
算法的基本思想: 第6章 内部排序 6.2 气泡排序 将待排序的记录看作是竖着排列的“气泡”,关键字较小 的记录比较轻,从而要往上浮。
排序 排序(sorting)是计算机程序设计中的一种重要操作,它的功能是将一个数据元素(或记录)的任意序列,重新排列成一个按关键字有序的序列。 由于待排序的记录数量不同,使得排序过程中涉及的存储器不同,可将排序方法分为两大类:一类是内部排序,指的是待排序记录存放在计算机存储器中进行的排序过程;另一类是外部排序,指的是待排序记录的数量很大,以致内存一次不能容纳全部记录,在排序过程中对外存进行访问的排序过程。
最小生成树 最优二叉树.
Presentation transcript:

本章重点难点 重点:插入排序、快速排序、选择排序、归并排序、基数排序的思想和算法。 难点:堆排序的思想和算法,在实际应用中如何根据实际情况,选择最优的排序算法。

第10章 内部排序 10.1 概述 10.2 插入排序 10.3 快速排序 10.4 选择排序 10.5 归并排序 10.6 基数排序 第10章 内部排序 10.1 概述 10.2 插入排序 10.3 快速排序 10.4 选择排序 10.5 归并排序 10.6 基数排序 10.7 内部排序方法的比较

10.1 概述 1、排序方法的稳定和不稳定 当需要排序的关键字都不相同时,排序的结果是唯一的; 张三 80分 李四 75分 王五 85分 张三 80分 李四 75分 王五 85分 陈六 90分 李四 75分 张三 80分 王五 85分 陈六 90分 陈六 90分 王五 85分 张三 80分 李四 75分

10.1 概述 当排序的关键字中存在相同的情况时,排序方法不唯一; 张三 80分 李四 75分 王五 85分 陈六 80分 李四 75分 张三 80分 李四 75分 王五 85分 陈六 80分 李四 75分 张三 80分 陈六 80分 王五 85分 李四 75分 陈六 80分 张三 80分 王五 85分 在排序前后,含相等关键字的记录的相对位置保持不变,称这种排序方法是稳定的; 反之,含相等关键字的记录的相对位置有可能改变,称这种排序方法是不稳定的。

10.1 概述 2. 内部排序和外部排序 在排序过程中,只使用计算机的内存存放待排序记录,称这种排序为内部排序。 排序期间文件的全部记录不能同时存放在计算机的内存中,要借助计算机的外存才能完成排序,称之为“外部排序”。 内外存之间的数据交换次数就成为影响外部排序速度的主要因素。

10.1 概述 3. 存储结构 #define MAXSIZE 1000 // 待排顺序表最大长度 typedef int KeyType; // 关键字类型为整数类型 typedef struct { KeyType key; // 关键字项 InfoType otherinfo; // 其它数据项 } RcdType; // 记录类型 typedef struct { RcdType r[MAXSIZE+1]; // r[0]闲置 int length; // 顺序表长度 } SqList; // 顺序表类型

10.1 概述 4. 效率分析 (1)时间复杂度: 关键字的比较次数和记录移动次数。 (2)空间复杂度: 执行算法所需的附加存储空间。 (3)稳定算法和不稳定算法

第10章 内部排序 10.1 概述 10.2 插入排序 10.3 快速排序 10.4 选择排序 10.5 归并排序 10.6 基数排序 第10章 内部排序 10.1 概述 10.2 插入排序 10.3 快速排序 10.4 选择排序 10.5 归并排序 10.6 基数排序 10.7 内部排序方法的比较

10.2、插入排序 10.2.1 直接插入排序 10.2.2 其他插入排序 10.2.3 希尔排序

10.2.1、直接插入排序 1、插入排序的思想 (1)一个记录是有序的; (2)从第二个记录开始,将每个记录插入到已排好序的序列中; (3)一直进行到第n个记录。

10.2.1、直接插入排序 2.算法概述 (1)将序列中的第1个记录看成是一个有序的子序列; (2)从第2个记录起逐个进行插入,直至整个序列变成按关键字有序序列为止; 整个排序过程需要进行比较、后移记录、插入适当位置。从第二个记录到第n个记录共需n-1趟。

10.2.1、直接插入排序 3.直接插入排序示例演示 49 38 65 38. 76 13 27 38 49 65 38. 76 13 27 38 49 65 38. 76 13 27 38 49 65 38. 76 13 27 65 38 49 38. 76 13 27 38. 38 49 65 76 13 27 38. 38 49 65 76 13 27 38. 38 49 65 76 13 27

10.2.1、直接插入排序 3.直接插入排序算法 void InsertionSort ( SqList &L ) { for ( i=2; i<=L.length; ++i ) if (L.r[i].key < L.r[i-1].key) { L.r[0] = L.r[i]; // 复制为监视哨 for ( j=i-1; L.r[0].key < L.r[j].key; -- j ) L.r[j+1] = L.r[j]; // 记录后移 L.r[j+1] = L.r[0]; // 插入到正确位置 } } // InsertSort

10.2.1、直接插入排序 3. 算法分析 (1)稳定性 直接插入排序是稳定的排序方法。 (2)算法效率 a.时间复杂度 最好情况:比较O(n),移动O(1); 最坏情况:比较O(n2),移动O(n2); 平均O(n2) b.空间复杂度 O(1)。

10.2.2、其它插入排序 1.折半插入排序思想 (1)在直接插入排序中,r[1..i-1] 是一个按关键字有序的有序序列; (2)可以利用折半查找实现“在r[1..i-1]中查找r[i]的插入位置”; (3)称这种排序为折半插入排序。

10.2.2、其它插入排序 2.折半插入排序的演示过程 0 1 2 3 4 5 6 7 8 9 10 查22 05 13 19 21 37 56 64 75 80 88 90 low mid= (low+high)/2 high mid high=mid-1 low=mid+1 mid low=mid+1 high=mid-1

10.2.2、其它插入排序 3.折半插入排序算法 void BiInsertionSort ( SqList &L ) { for ( i=2; i<=L.length; ++i ) { L.r[0] = L.r[i]; // 将 L.r[i] 暂存到 L.r[0] 在 L.r[1..i-1]中折半查找插入位置; for ( j=i-1; j>=high+1; --j ) L.r[j+1] = L.r[j]; // 记录后移 L.r[high+1] = L.r[0]; // 插入 } // for } // BInsertSort

10.2.2、其它插入排序 low = 1; high = i-1; while (low<=high) { m = (low+high)/2; // 折半 if (L.r[0].key < L.r[m].key) high = m-1; // 插入点在低半区 else low = m+1; // 插入点在高半区 }

10.2.2、其它插入排序 4. 2路插入排序示例演示 分治的思想 例:49, 38, 65, 97, 76, 13, 27, 49* ***

10.2.2、其它插入排序 5. 表插入排序的思想 (1)目的是为了减少在排序过程中进行的 “移动”记录的操作; 5. 表插入排序的思想 (1)目的是为了减少在排序过程中进行的 “移动”记录的操作; (2)利用静态链表进行排序,排序中只改为指针; (3)在排序完成之后,一次性地调整各个记录相互之间的位置。

10.2.2、其它插入排序 5. 表插入排序的存储结构 存储结构: #define SIZE 100 typedef struct { 5. 表插入排序的存储结构 存储结构: #define SIZE 100 typedef struct { RcdType rc; int next; }SLNode; typedef struct { SLNode r[SIZE]; int length; }SLinkListType;

10.2.2、其它插入排序 6. 表插入排序的示例演示 1 2 3 4 5 6 7 8 初始 状态 key域 next域 M 49 38 6. 表插入排序的示例演示 1 2 3 4 5 6 7 8 初始 状态 key域 next域 M 49 38 65 97 76 13 27 49* 1 - M 49 38 65 97 76 13 27 49* 2 1 - M 49 38 65 97 76 13 27 49* 2 3 1 - M 49 38 65 97 76 13 27 49* 2 3 1 4 -

10.2.2、其它插入排序 7. 表插入排序的算法 void LInsertionSort (SLinkListType &SL){ 7. 表插入排序的算法 void LInsertionSort (SLinkListType &SL){ // 对记录序列SL[1..n]作表插入排序 SL.r[0].key = MAXINT ; SL.r[0].next = 1; SL.r[1].next = 0; for ( i=2; i<=n; ++i ) for ( j=0, k = SL.r[0].next;SL.r[k].key<= SL.r[i].key ; j=k, k=SL.r[k].next ) { SL[j].next = i; SL[i].next = k; } // 结点i插入在结点j和结点k之间 }// LinsertionSort

10.2.2、其它插入排序 7. 表插入排序的示例演示 i=1 p=6 q=7 i=2 p=7 q=2 i=3 p=2 q=1 i=4 7. 表插入排序的示例演示 1 2 3 4 5 6 7 8 i=1 p=6 q=7 M 49 38 65 97 76 13 27 49* 6 8 1 5 4 7 2 3 i=2 p=7 q=2 M 13 38 65 97 76 49 27 49* 6 (6) 1 5 4 8 2 3 i=3 p=2 q=1 M 13 27 65 97 76 49 38 49* 6 (6) (7) 5 4 8 1 3 i=4 p=1 q=8 M 13 27 38 97 76 49 65 49* 6 (6) (7) 4 8 5 3 p=SL.r[p].next

10.2.2、其它插入排序 如何在排序之后调整记录序列? 算法中使用了三个指针: 其中:p指示第i个记录的当前位置 i指示第i个记录应在的位置 q指示第i+1个记录的当前位置

10.2.2、其它插入排序 8. 表插入排序的记录调整算法 **** void Arrange (SLinkListType &SL) { 8. 表插入排序的记录调整算法 void Arrange (SLinkListType &SL) { p = SL.r[0].next; // p指示第一个记录的当前位置 for ( i=1; i<Sl.length; ++i ) { while (p<i) p = SL.r[p].next; q = SL.r[p].next; // q指示尚未调整的表尾 if ( p!= i ) { SL.r[p]←→SL.r[i]; // 交换记录,使第i个记录到位 SL.r[i].next = p; // 指向被移走的记录 } p = q; // p指示尚未调整的表尾, // 为找第i+1个记录作准备 } // Arrange ****

10.2.3、希尔排序 1. 希尔排序的思想 (1)对待排记录序列先作“宏观”调整,再作“微观”调整。 1. 希尔排序的思想 (1)对待排记录序列先作“宏观”调整,再作“微观”调整。 (2)所谓“宏观”调整,指的是,“跳跃式” 的插入排序。

10.2.3、希尔排序 2. 希尔排序概述 (1)将记录序列分成若干子序列,分别对每个子序列进行插入排序。 2. 希尔排序概述 (1)将记录序列分成若干子序列,分别对每个子序列进行插入排序。 例如:将 n 个记录分成 d 个子序列: {R[1],R[1+d],R[1+2d],…,R[1+kd]} {R[2],R[2+d],R[2+2d],…,R[2+kd]} …………………………………… {R[d],R[2d],R[3d],…,R[kd],R[(k+1)d]} (2)其中,d 称为增量,它的值在排序过程中从大到小逐渐缩小,直至最后一趟排序减为 1。

10.2.3、希尔排序 3. 希尔排序演示 16 25 12 30 47 11 23 36 9 18 31 第一趟希尔排序,设增量 d =5 3. 希尔排序演示 16 25 12 30 47 11 23 36 9 18 31 第一趟希尔排序,设增量 d =5 11 23 12 9 18 16 25 36 30 47 31 第二趟希尔排序,设增量 d = 3 9 18 12 11 23 16 25 31 30 47 36 第三趟希尔排序,设增量 d = 1 9 11 12 16 18 23 25 30 31 36 47

10.2.3、希尔排序 3. 希尔排序算法 void ShellInsert ( SqList &L, int dk ) { 3. 希尔排序算法 void ShellInsert ( SqList &L, int dk ) { for ( i=dk+1; i<=L.length; ++i ) if (LT(L.r[i].key, L.r[i-dk].key)) { L.r[0] = L.r[i]; // 暂存在R[0] for (j=i-dk; j>0&&LT(L.r[0].key,L.r[j].key); j-=dk) L.r[j+dk] = L.r[j]; // 记录后移,查找插入位置 L.r[j+dk] = L.r[0]; // 插入 }

10.2.3、希尔排序 3. 希尔排序算法 void ShellSort (SqList &L, int dlta[], int t) 3. 希尔排序算法 void ShellSort (SqList &L, int dlta[], int t) { // 增量为dlta[]的希尔排序 for (k=0; k<t; ++k) ShellInsert(L, dlta[k]); //一趟增量为dlta[k]的插入排序 }

10.2.3、希尔排序 4. 希尔排序算法分析 (1)稳定性 希尔排序是不稳定的排序方法。 (2)算法效率 a.时间复杂度 4. 希尔排序算法分析 (1)稳定性 希尔排序是不稳定的排序方法。 (2)算法效率 a.时间复杂度 平均O(n1.3)到平均O(n1.5) b.空间复杂度 O(1)。

第10章 内部排序 10.1 概述 10.2 插入排序 10.3 快速排序 10.4 选择排序 10.5 归并排序 10.6 基数排序 第10章 内部排序 10.1 概述 10.2 插入排序 10.3 快速排序 10.4 选择排序 10.5 归并排序 10.6 基数排序 10.7 内部排序方法的比较

10.3 快速排序 一、起泡排序 二、快速排序

一、起泡排序 1.基本思想: (1)从第一个记录开始,两两记录比较,若F[1].key>F[2].key,则将两个记录交换; (2)第1趟比较结果将序列中关键字最大的记录放置到最后一个位置,称为“沉底”,而最小的则上浮一个位置; (3)n个记录比较n-1遍(趟)。

一、起泡排序 2.示例演示: 1 6 2 3 4 5 1 2 6 3 4 5 1 2 3 6 4 5 1 2 3 4 6 5 1 2 3 4 5 6 6 1 2 3 4 5 第一趟 1 2 3 4 5 6 第二趟

一、起泡排序 void BubbleSort(SqList &L ) {int i,j,noswap; SqList temp; for(i=1;i<=n-1;i++) {noswap=TRUE; for(j=1;j<=n-i;j++) if (L.r[j].key>L.r[j+1].key) {temp=L.r[j]; L.r[j]=L.r[j+1]; L.r[j+1]=temp; noswap=FALSE; } if (noswap) break; 3.算法:

一、起泡排序 * 4、算法分析: (1)稳定性 起泡排序是稳定的排序方法。 (2)时间是复杂性 最好情况:比较O(n),移动O(1) 最坏情况:比较O(n2),移动O(n2) 平均情况:O(n2) (3)空间复杂性 O(1) *

二、快速排序 1. 基本思想 (1)左侧子序列中所有对象的关键字都小于或等于对象v的关键字;

二、快速排序 2. 示例演示 初始关键字 49 49* 65 97 17 27 50 i j j 一次交换 27 49* 65 97 17 49 50 i i j 二次交换 27 49* 49 97 17 65 50 i j 三次交换 27 49* 17 97 49 65 50 i j 四次交换 27 49* 17 49 97 65 50 i j 完成一趟排序

二、快速排序 3. 算 法 初始关键字 49 49* 65 97 17 27 50 low high high 3. 算 法 初始关键字 49 49* 65 97 17 27 50 low high high pivotkey=L.r[low].key; while ((low<high)&& (L.r[high].key>=pivotkey)) --high; L.r[low] ←→ L.r[high]; 一次交换 27 49* 65 97 17 49 50 low high low while ((low<high)&& (L.r[low].key<=pivotkey)) ++low; L.r[low] ←→ L.r[high];

二、快速排序 3. 算 法 int Partition(SqList &L, int low, int high) 3. 算 法 int Partition(SqList &L, int low, int high) { KeyType pivotkey; pivotkey = L.r[low].key; while (low<high) { while ((low<high)&& (L.r[high].key>=pivotkey)) --high; L.r[low] ←→ L.r[high]; while ((low<high)&& (L.r[low].key<=pivotkey)) ++low; } return low; // 返回枢轴位置 } // Partition

二、快速排序 4. 算法改进 初始关键字 49 49* 65 97 17 27 50 i j j 一次交换 27 49* 65 97 17 50 j i i

二、快速排序 4. 算法改进 int Partition(SqList &L, int low, int high) {KeyType pivotkey; L.r[0] = L.r[low]; pivotkey = L.r[low].key; while (low<high) { …………………………………. } L.r[low] = L.r[0]; // 枢轴记录到位 return low; // 返回枢轴位置 } // Partition

二、快速排序 4. 算法改进 while (low<high && L.r[high].key>=pivotkey) L.r[low] = L.r[high]; while (low<high && L.r[low].key<=pivotkey) ++low; L.r[high] = L.r[low];

二、快速排序 4. 算法改进 void QSort(SqList &L, int low, int high) { int pivotloc; if (low < high) { pivotloc = Partition(L, low, high); // 将L.r[low..high]一分为二 QSort(L, low, pivotloc-1); // 对低子表递归排序,pivotloc是枢轴位置 QSort(L, pivotloc+1, high); // 对高子表递归排序 }

二、快速排序 5. 算法分析 (1)稳定性 快速排序是不稳定的排序方法。 (2)时间复杂度 最坏情况: 1,2,3,…,n n,n-1,…2,1。 比较O(n2), 移动O(n2) n,n-1,…2,1。

二、快速排序 5. 算法分析 最好情况是每次选择的基准把左右分成相等两部分: C(n)≤n+2C(n/2) ≤n+2(n/2+2C(n/4))=2n+22C(n/22) …… ≤kn+2kC(n/2k) 最后组中只有一个元素:n=2k,k=log2n, C(n)≤nlog2n+nC(1) 最好情况的时间复杂度为O(nlog2n) 平均时间复杂度也是O(nlog2n)

二、快速排序 (3)空间复杂度 由于快速排序是一个递归过程,需一个栈的附加空间,栈的平均深度为O(log2n)。 QUICKSORT(s,t,A) LIST F; int s,t; {int i; if (s<t) {i=PARTITION(s,t,A); QUICKSORT(s,i-1,A); QUICKSORT(i+1,t,A); } 假如数组元素下标为1…n。 1 … n/2k n/2k-1 n/23 n/4 n/22 n/2 n

第10章 内部排序 10.1 概述 10.2 插入排序 10.3 快速排序 10.4 选择排序 10.5 归并排序 10.6 基数排序 第10章 内部排序 10.1 概述 10.2 插入排序 10.3 快速排序 10.4 选择排序 10.5 归并排序 10.6 基数排序 10.7 内部排序方法的比较

10.4 选择排序 10.4.1 简单选择排序 10.4.2 树形选择排序 10.4.3 堆排序

10.4.1、简单选择排序 1.基本思想 (1)第一次从n个关键字中选择一个最小值,确定第一个; (2)第二次再从剩余元素中选择一个最小值,确定第二个; (3)共需n-1次选择。

10.4.1、简单选择排序 2.操作过程 设需要排序的表是A[n+1]: (1)第一趟排序是在无序区A[1]到A[n]中选出最小的记录,将它与A[1]交换,确定最小值; (2)第二趟排序是在A[2]到A[n]中选关键字最小的记录,将它与A[2]交换,确定次小值; (3)第i趟排序是在A[i]到A[n]中选关键字最小的记录,将它与A[i]交换; (4)共n-1趟排序。

10.4.1、简单选择排序 3. 算 法 void SelectSort(SqList &L) {int i,j,low; 3. 算 法 void SelectSort(SqList &L) {int i,j,low; for(i=1;i<L.length;i++) {low=i; for(j=i+1;j<=L.length;j++) if(L.r[j].key<L.r[low].key) low=j; if(i!=low) {L.r[0]=L.r[i];L.r[i]=L.r[low];L.r[low]=L.r[0]; }

10.4.1、简单选择排序 * 4. 算法分析 (1)稳定性 简单选择排序方法是稳定的。 (2)时间复杂度 比较O(n2),移动最好O(1),最差O(n) (3)空间复杂度 为O(1)。 *

10.4.2、树形选择排序 1、引入 树形选择排序,又称锦标赛排序:按锦标赛的思想进行排序,目的是减少选择排序中的重复比较次数。 例如: 4,3,1,2 在选择排序中3和4的比较次数共发生了三次。 *

10.4.2、树形选择排序 2、示例演示 6 6 8 9 6 17 8 6 10 9 20 8 9 90 17 输出6

10.4.2、树形选择排序 2、示例演示 8 9 8 9 20 17 8  10 9 20 8 9 90 17 输出8

10.4.2、树形选择排序 * 3. 算法分析 (1)稳定性 树形选择排序方法是稳定的。 (2)时间复杂度 比较O(nlog2n) (3)空间复杂度 为O(n)。 *

10.4.3、堆排序 1、引 入 堆排序属于选择排序:出发点是利用前一次比较的结果,减少“比较”的次数。 *

10.4.3、堆排序 2.堆的定义 n个元素的序列A[1].key,A[2].key,…,A[n].key,当且仅当满足下述关系时,称之为堆。 A[i].key≤A[2*i].key 且 A[i].key≤A[2*i+1].key A[i].key≥A[2*i].key A[i].key≥A[2*i+1].key 小根堆 大根堆

10.4.3、堆排序 3、小根堆例子 0 1 2 3 4 5 6 7 8 12 22 34 40 30 36 50 41 12 22 34 40 30 36 50 41 小根(顶)堆

10.4.3、堆排序 4、大根堆例子 0 1 2 3 4 5 6 7 8 87 50 36 40 30 34 12 22 87 50 36 40 30 34 12 22 大根(顶)堆

10.4.3、堆排序 5.利用大根堆进行排序的示例演示 87 87 50 36 40 30 34 12 22 50 36 22 50 36 40 30 34 12 87 40 30 34 12 22 22 50 36 40 30 34 12 * 87

10.4.3、堆排序 6.堆排序的思想 堆排序需解决两个问题: a. 由一个无序序列建成一个堆。 b. 在输出堆顶元素之后,调整剩余元素成为一个新的堆。 *

10.4.3、堆排序 7.堆排序的算法(采用大根堆) a. 按关键字建立A[1],A[2],…A[n]的大根堆; b. 输出堆顶元素,采用堆顶元素A[1]与最后一个元素A[n]交换,最大元素得到正确的排序位置; c. 此时前n-1个元素不再满足堆的特性,需重建堆; d. 循环执行b,c两步,到排序完成。

10.4.3、堆排序 8.算法示例演示 例1:对无序序列{50,38,48,97,49,13,27,65}进行堆排序。 1)先建一个完全二叉树: 50 2)从最后一个非终端结点开始建堆; n个结点,最后一个非终端结点的下标是n/2 38 48 97 49 13 27 65

10.4.3、堆排序 50 50 38 48 97 48 97 49 13 27 38 49 13 27 65 65 50 97 97 48 65 48 65 49 13 27 50 49 13 27 38 38 *

10.4.3、堆排序 50 s 38 78 49 j s j 75 78 65 64 63 62 m j

10.4.3、堆排序 9 筛选算法代码 void HeapAdjust(HeapType &H, int s, int m) {int j; RedType rc; rc = H.r[s]; for (j=2*s; j<=m; j*=2) {if (j<m && H.r[j].key<H.r[j+1].key) ++j; if (rc.key >= H.r[j].key) break; H.r[s] = H.r[j]; s = j; } H.r[s] = rc; // 插入 } // HeapAdjust

10.4.3、堆排序 10 建堆算法代码 for (i=H.length/2; i>0; --i) HeapAdjust ( H, i, H.length );

10.4.3、堆排序 38 97 65 27 65 48 50 48 50 49 13 27 38 49 13 65 27 38 97 97 13 50 49 48 38 27 13 50 65 97

10.4.3、堆排序 11 堆排序算法代码 void HeapSort(HeapType &H) { int i; RcdType temp; for (i=H.length/2; i>0; --i) HeapAdjust ( H, i, H.length ); for (i=H.length; i>1; --i) { temp=H.r[i]; H.r[i]=H.r[1]; H.r[1]=temp; HeapAdjust(H, 1, i-1); } } // HeapSort *

10.4.3、堆排序 12 算法分析 a.堆排序是不稳定的排序。 b.时间复杂度为O(nlog2n)。 c.空间复杂度为O(1)。 {2,38,38} 38 2 38 2 38 38 38 2 38

第10章 内部排序 10.1 概述 10.2 插入排序 10.3 快速排序 10.4 选择排序 10.5 归并排序 10.6 基数排序 第10章 内部排序 10.1 概述 10.2 插入排序 10.3 快速排序 10.4 选择排序 10.5 归并排序 10.6 基数排序 10.7 内部排序方法的比较

10.5 归并排序 1、归并的定义 又叫合并,两个或两个以上的有序序列合并成一个有序序列。

10.5 归并排序 2、归并示例演示 i m n SR[] j i i j j j i 10.5 归并排序 2、归并示例演示 i m n SR[] 08 21 25 49 62 72 93 16 22 23 j i i j j j i for (j=m+1, k=i; i<=m && j<=n; ++k) { if LQ(SR[i].key,SR[j].key) TR[k] = SR[i++]; else TR[k] = SR[j++]; } i n TR[] 08 16 21 22 23 25 25 49 62 72 93 k k k k k

10.5 归并排序 2、归并示例演示 i m n SR[] j i i j j j i if (i<=m) 10.5 归并排序 2、归并示例演示 i m n SR[] 08 21 25 49 62 72 93 16 22 23 j i i j j j i if (i<=m) while (k<=n && i<=m) TR[k++]=SR[i++]; if (j<=n) while (k<=n &&j <=n) TR[k++]=SR[j++]; i n TR[] 08 16 21 22 23 25 25 49 62 72 93 k k k k k

10.5 归并排序 2、归并算法 void Merge (RcdType SR[], RcdType TR[], 10.5 归并排序 2、归并算法 void Merge (RcdType SR[], RcdType TR[], int i, int m, int n) { int j,k; ……………………….. } // Merge

10.5 归并排序 2、归并算法 for (j=m+1, k=i; i<=m && j<=n; ++k) { 10.5 归并排序 2、归并算法 for (j=m+1, k=i; i<=m && j<=n; ++k) { if LQ(SR[i].key,SR[j].key) TR[k] = SR[i++]; else TR[k] = SR[j++]; } if (i<=m) while (k<=n && i<=m) TR[k++]=SR[i++]; if (j<=n) while (k<=n &&j <=n) TR[k++]=SR[j++];

10.5 归并排序 3、2-路归并排序方法示例 例1 给定排序码25,57,48,37,12,92,86,写出二路归并排序过程。 A[] 10.5 归并排序 3、2-路归并排序方法示例 例1 给定排序码25,57,48,37,12,92,86,写出二路归并排序过程。 A[] 25 57 48 37 12 92 86 B[] 25 57 37 48 12 92 86 一趟 A[] 25 37 48 57 12 86 92 二趟 B[] 12 25 37 48 57 86 92 三趟

10.5 归并排序 4、2-路归并排序方法思想 (1) 将n个记录看成是n个长度为1的有序子表; 10.5 归并排序 4、2-路归并排序方法思想 (1) 将n个记录看成是n个长度为1的有序子表; (2) 将两两相邻的有序子表进行归并,若子表数为奇数,则留下的一个子表直接进入下一次归并; (3) 重复步骤(2),直到归并成一个长度为n的有序表。

10.5 归并排序 5、2-路归并排序核心算法 void Msort(RcdType A[],RcdType B[],int n, int l) {int i=1,t; while (i+2*l-1<=n); {Merge (A,B,i,i+l-1,i+2*l-1) i=i+2*l; } …………………… R[] … i=1 l 2*l i+2l-1 i i+l-1

10.5 归并排序 5、2-路归并排序核心算法 void Msort(RcdType A[],RcdType B[],int n, int l) {…………. if (i+l-1<n) Merge(A,B,i,i+l-1,n); else for (t=i;t<=n;t++) B[t]=A[t]; } n … i+l-1 i+2l-1 i

10.5 归并排序 6、2-路归并排序算法 void MergeSort(RcdType A[],int n) {int l=1; 10.5 归并排序 6、2-路归并排序算法 void MergeSort(RcdType A[],int n) {int l=1; Rcdtype B[]; while (l<n) {mpass(A,B,n,l) l=2*l; mpass(B,A,n,l); }

10.5 归并排序 7、2-路归并排序算法(递归) 将记录SR[s],SR[s+1],…,SR[T]分成两部分; 10.5 归并排序 7、2-路归并排序算法(递归) 将记录SR[s],SR[s+1],…,SR[T]分成两部分; SR[s],…,SR[(s+t)/2] 和SR[(s+t)/2+1],…,SR[t] (2)分别在第两个序列上进行归并排序; (3)调用Msrge()函数把两个有序序列合并成一个。

10.5 归并排序 7、2-路归并排序算法(递归) void MSort(RedType SR[], RedType TR1[], int s, int t) { int m; RedType TR2[]; if (s==t) TR1[t] = SR[s]; else { m=(s+t)/2; MSort(SR,TR2,s,m); MSort(SR,TR2,m+1,t); Merge(TR2,TR1,s,m,t); } } // MSort

10.5 归并排序 7、2-路归并排序算法(递归) void MergeSort(SqList &L) { // 算法10.14 10.5 归并排序 7、2-路归并排序算法(递归) void MergeSort(SqList &L) { // 算法10.14 // 对顺序表L作归并排序。 SqList L1 MSort(L.r, L1.r, 1, L.length); }

10.5 归并排序 8、2-路归并排序算法(递归) (1).稳定性 归并排序是稳定的排序方法。 (2).时间复杂度 10.5 归并排序 8、2-路归并排序算法(递归) (1).稳定性 归并排序是稳定的排序方法。 (2).时间复杂度 每趟归并所花时间比较移动都是O(n); 第i趟归并有序序列长度为2i;假设共需k趟归并, 最后长度为n,约为2k=n;k=log2n; 时间复杂度为O(nlog2n)。 (3).空间复杂度 是O(n)。 **

思考题 例 在二路归并排序算法中,起初,把每个元素A[i]分别看成一个排序序列,我们可以改进这种方法;对给定的A,若 A[i].key<=A[i+1].key<=…<=A[j].key 则把A[i],…,A[j]作为一个初始的排序序列. 请重新设计归并排序的有关函数. 26 15 77 1 61 11 59 15 48 19 18 26,15 77,1 61,11 59,15 48,19,18

答案 A[] int k=0,C[100]; C[0]=0; for(i=1;i<=n;i++) 26 15 77 1 61 11 59 48 19 18 int k=0,C[100]; C[0]=0; for(i=1;i<=n;i++) if(i==n||A[i].key>A[i+1].key) {k++;C[k]=i;} C[] 1 3 5 7 9 10 11

答案 mpass(int n,int k,LIST A,LIST B) {int i,j=k,k=0; for (i=0;i<=j-2;i=i+2) { merge(C[i]+1,C[i+1],C[i+2],A,B); C[++k]=C[i+2]; } if(i==j-1) {for (t=C[i]+1;t<=n;t++) B[t]=A[t]; C[++k]=n;

答案 int k=0,C[100]; C[0]=0; void SORT(int n,LIST A) {LIST B,C; for(i=1;i<=n;i++) {if(i==n||A[i].key>A[i+1].key) {k++;C[k]=i;} } while (k>1) {mpass(n,k,A,B) mpass(n,k,B,A); **

第10章 内部排序 10.1 概述 10.2 插入排序 10.3 快速排序 10.4 选择排序 10.5 归并排序 10.6 基数排序 第10章 内部排序 10.1 概述 10.2 插入排序 10.3 快速排序 10.4 选择排序 10.5 归并排序 10.6 基数排序 10.7 内部排序方法的比较

10.6 基数排序 10.6.1 基数排序的起源 10.6.2 基数排序的事例演示 10.6.3 多关键字的排序 10.6.4 键式基数排序

10.6.1 基数排序的起源 例如:4,2,5,8,1,2 1 2,2 4 5 8 0 1 2 3 4 5 6 7 8 9 10 1、箱(桶)排序的思想:设置若干个箱子(桶),依次扫描待排序的记录,A[1],A[2],…,A[n],把关键字为k的记录放在第k个箱子里,按序号将非空的箱子里的记录收集起来。 2、箱(桶)排序的缺点:如果关键字位数太大,这样做空间复杂度和时间复杂度都太大。 *

10.6.1 基数排序的起源 例如:21,22,11,12 21 11 22 12 0 1 2 3 4 5 收集:21,11,22,12 11 12 21 22 0 1 2 3 4 5 收集:11,12,21,22

10.6.2 基数排序的事例演示 Q[0] 890 210 Q[1] 321 901 Q[2] 432 012 例如:321 986 123 432 543 018 765 678 987 789 098 890 109 901 210 012 Q[3] 123 543 Q[4] Q[5] 765 Q[6] 986 Q[7] 987 Q[8] 018 678 098 Q[9] 789 109

10.6.2 基数排序的事例演示 Q[0] 901 109 Q[1] 210 012 018 Q[2] 321 123 890 210 321 901 432 012 123 543 765 986 987 018 678 098 789 109 Q[3] 432 Q[4] 543 Q[5] Q[6] 765 Q[7] 678 Q[8] 986 987 789 Q[9] 890 098

10.6.2 基数排序的事例演示 Q[0] 012 018 098 Q[1] 109 123 Q[2] 210 901 109 210 012 018 321 123 432 543 765 678 986 987 789 809 098 Q[3] 321 Q[4] 432 Q[5] 543 Q[6] 678 Q[7] 765 789 Q[8] 890 Q[9] 901 986 987

10.6.3 多关键字的排序 一、排序过程 二、存储结构 三、排序算法 四、存在问题

一、排序过程 排序的过程主要是分配与收集,又称分配排序。 设待排记录A的关键字是figure位的正整数。 1、从最低位(个位)开始,扫描关键字的pass位,把等于0的插入Q[0],…,等于9的插入Q[9]。 2、将Q[0],…,Q[9]中的数据依次收集到A[]中。 3、pass+1直到figure,重复执行1,2两步 *

二、存储结构 struct queue struct records {records elements[m]; {keytype key; 2、队列的存储结构 1、待排记录 struct queue {records elements[m]; int front; int rear; } queue Q[10]; struct records {keytype key; fields other; } 3、待排序记录的存储 Queue A *

三、排序算法 int RADIX(int k,int p) { return((k/pow10(p-1))%10); }

三、排序算法 void radixsort(figure,A) int figure;QUEUE &A; {QUEUE Q[10]; records data; int pass,r,i;//pass用于位数循环,r取位数 for(pass=1;pass<=figure;pass++) 把10个队列置空 while(!EMPTY(A)) {取A中元素dada,计算data的关键字的第pass位的值r,放入队列Q[r]中; } 把10个队列中的值依次收集到A中 }

三、排序算法 void radixsort(figure,A) int figure;QUEUE &A; {QUEUE Q[10]; records data; int pass,r,i;//pass用于位数循环,r取位数 for(pass=1;pass<=firure;pass++) for(i=0;i<=9;i++) MAKENULL(Q[i]) while(!EMPTY(A)) {data=FRONT(A); DEQUEUE(A); r=RADIX(data.key,pass); ENQUEUE(data,Q[r]); }

三、排序算法 For(i=0;i<=9;i++) While(!EMPTY(Q[i])) {data=FRONT(Q[i]); DEQUEUE(Q[i]); ENQUEUE(data,A); }

四、存在问题 如果采用顺序队列,队列的长度怎么确定? 110 920 230 030 090 320 100 400 503 765 678 986 987 789 890 098 如果采用数组表示队列,队列的长度很难确定,太大造成浪费,小了会产生溢出。 一般采用链队列.

10.6.4 键式基数排序 一、存储结构 二、事例演示 三、排序算法 四、算法分析

一、存储结构 链队列的存储结构 struct celltype{ records element; celltype *next } struct QUEUE{ celltype *front; celltype *rear; } QUEUE Q[10];

二、事例演示 Q0 012 018 098 ^ Q1 109 123 ^ Q2 210

三、排序算法 1、Q[0]的尾指针的next域指向Q[1]的第一个元素所在的结点。 2、Q[0]的尾指针指向Q[1]的尾指针。 void CONCATENATE(QUEUE &Q[0],QUEUE &Q[1]) { if(!EMPTY(Q[1])) Q[0].rear->next=Q[1].front->next; Q[0].rear=Q[1].rear; }

三、排序算法 For(i=0;i<=9;i++) While(!EMPTY(Q[i])) {data=FRONT(Q[i]); DEQUEUE(Q[i]); ENQUEUE(data,A); } 原队列收集操作 for(i=1;i<=9;i++) CONCATENATE(Q[0],Q[i]); A=Q[0]; 改为:

四、算法分析 基数排序是稳定的 时间复杂性与空间复杂性分析: 设关键字位数为d 则时间复杂性为O(dn) 考虑到d是一个常数 时间复杂性为O(n) 空间复杂性O(n) ***

第10章 内部排序 10.1 概述 10.2 插入排序 10.3 快速排序 10.4 选择排序 10.5 归并排序 10.6 基数排序 第10章 内部排序 10.1 概述 10.2 插入排序 10.3 快速排序 10.4 选择排序 10.5 归并排序 10.6 基数排序 10.7 内部排序方法的比较

10.7 内部排序方法的比较 n n2 n2 n n2 n2 n2 n2 n n n2 √ 1 √ 1 nlog2n × log2n 1 √ 比较次数 移动次数 稳定 性 附加存储 最好 最差 直接插入排序 冒泡排序 快速排序 简单选择排序 堆排序 归并排序 基数排序 n n2 n2 √ 1 n n2 n2 √ 1 nlog2n n2 n2 × log2n n n n2 1 √ nlog2n nlog2n × 1 nlog2n nlog2n √ n dn …… √ n

本章小结 熟练掌握:直接插入排序、希尔排序、冒泡排序、快速排序、简单选择排序、堆排序、归并排序、基数排序的思想和算法。充分了解各种排序算法的应用背景和优缺点。 加强各种排序算法在实际应用中的训练,提高实际应用水平。