第六章 常见排序算法

上章回顾

二叉树的定义

树深度的定义

什么样的二叉树是满二叉树

中序遍历的规则

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

第六章

第六章

常见排序算法

常见排序算法

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

预习检查

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

课程目标

本章概述

难点

几种常见排序算法。

本章目标

熟悉常见的查找算法和排序算法

快速排序算法

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

本章结构

数据结构与算法初步

数据结构与算法初步 常见的排序算法

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

常见的排序算法

                   6.1 常见的排序算法 冒泡排序

快速排序

直接插入排序

希尔排序

选择排序

堆排序

归并排序

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                                 6.1.1 冒泡排序 算法描述

设待排序记录序列中的记录个数为n

一般地,第i趟起泡排序从1到n-i+1

依次比较相邻两个记录的关键字,如果发生逆序,则交换之

其结果是这n-i+1个记录中,关键字最大的记录被交换到第n-i+1的位 置上,最多作n-1趟。

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                                                    6.1.1 冒泡排序 算法实例

2549012345

21

25*

16

0849

2525*212516

21

16

08 25*

chang=149

08[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

chang=149

16082525*[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

21

chang=1

25*

                              6.1.1 冒泡排序 算法实例

i =449

i

1608212525*49 012345

i =549

i

0816212525*49

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

chang=1

chang=0

                                                     6.1.1 冒泡排序 算法实例

21212525

21211608

49

2516081608

08

25

16

08

49

49 49 49 49

初始 关键 字

第一 第二 第三 第四 第五

251608

16212125252525252525

49 49 49 49 49

趟排 趟排 趟排 趟排 趟排 嵌入式序家园 www.embedclub.com序 序

[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                        6.1.1 冒泡排序 算法实现

#include <stdio.h> main()

输入n 个数给a[1] 到 a[n] for j=1 to n-1

{

int a[11],i,j,t;

printf("Input 10 numbers:\n"); for(i=1;i<11;i++)

for i=1 to n-j

真 a[i]>a[i+1] 假

scanf("%d",&a[i]);

a[i]⇔a[i+1] 输出a[1] 到 a[n]

for(i=1;i<=10-j;i++)

[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git}

[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

printf("\n");

for(j=1;j<=9;j++)

if(a[i]>a[i+1])

{t=a[i]; a[i]=a[i+1]; a[i+1]=t;}

printf("The sorted numbers:\n");

for(i=1;i<11;i++) printf("%d ",a[i]);

                                   6.1.2 快速排序 算法特点:

快速排序是通过比较关键码、交换记录, 以某个记录为界(该记录称为支点),将待排序列分成两部分

一部分所有记录的关键码大于等于支点记录的关键码

另一部分所有记录的关键码小于支点记录的关键码

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                                                     6.1.2 快速排序 算法描述:

任取待排序记录序列中的某个记录(例如取第一个记录)作为基准(枢),按照该记录的 关键字大小,将整个记录序列划分为左右两个子序列

左侧子序列中所有记录的关键字都小于或等于基准记录的关键字

右侧子序列中所有记录的关键字都大于基准记录的关键字

基准记录则排在这两个子序列中间(这也是该记录最终应安放的位置)。

然后分别对这两个子序列重复施行上述方法,直到所有的记录都排在相应位置上为

止。

基准记录也称为枢轴(或支点)记录。 取序列第一个记录为枢轴记录,其关键字为Pivotkey 指针low指向序列第一个记录位置 指针high指向序列最后一个记录位置

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                                                                  6.1.2 快速排序 算法实例:

始关键字 pivotkey

21low

25492549

25*1625*16

08high

一次交换 二次交换 三次交换 high-1

210808

low low

high

完成一趟排序

16

1621

25*49high

08

25*

high

08

low low

25*49high

2525

08

[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

491649

25*16high

2525

low

                             6.1.2 快速排序 算法实例:

完成一趟排序

08162125*4925

分别进行快速排序

08 16 21

08 16 21 25*

49 2549

有序序列

08162125*

2549

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

15

                               6.1.2 快速排序 算法分析:

快速排序是一个递归过程; 利用序列第一个记录作为基准,将整个序列划分为左右两个子序列。只要

是关键字小于基准记录关键字的记录都移到序列左侧;

快速排序的趟数取决于递归树的高度。

如果每次划分对一个记录定位后, 该记录的左侧子序列与右侧子序列的长 度相同, 则下一步将是对两个长度减半的子序列进行排序, 这是最理想的情 况

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

16

                          6.1.3 直接插入排序 算法描述:

记录存放在数组R[0....n-1]中,排序过程的某一中间时刻,R被划分 成两个子区间R[0...i-1]和R[i....n-1],其中:前一个子区间是已排好 序的有序区;后一个子区间则是当前未排序的部分。

基本操作

将当前无序区的第1个记录R[i]插入到有序区R[0....i-1]中适当的位置 ,使R[0...i]变为新的有序区

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                               6.1.3 直接插入排序 操作细节:

当插入第i(i≥1)个对象时, 前面的r[0], r[1], ..., r[i-1]已经排 好序。

用r[i]的关键字与r[i-1], r[i-2], ...的关键字顺序进行比较(和顺 序查找类似),如果小于,则将r[x]向后移动(插入位置后的记录向 后顺移)

找到插入位置即将r[i]插入

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                             6.1.3 直接插入排序 实用例子:

已知待序的一组记录的初始排列为:21, 25, 49, 25*, 16, 08

254925*012345

21

16

08

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                                               6.1.3 直接插入排序 实用例子:

i=1 i=1

254925* 25 2125 25* 160825

i=2 i=2

21012345

i=3 i=3

21

012345

temp

temp

4949 2549 25*160849

254925*160825*012345

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                                                    6.1.3 直接插入排序 实用例子:

i=4 i=4

212525*4916

160816

215

2525*

i=完成

16

0808 08 08

0 1 2 3 4 5 temp

49

0 1 2 3 4 5 temp

08

16

21

2525*

49

01234

[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git5

[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

            6.1.3 直接插入排序 算法实现:

void InsertSort (int r[ ], int n ) {

// 假设关键字为整型,放在向量r[]int i, j, temp;

for (i = 1;i< n;i++ )

{

temp = r[i];

for(j = i;j>0;j- -) {//从后向前顺序比较,并依次后移

}

r[j] = temp;

if ( temp < r[j-1] ) r[j] = r[j-1];

else

break;

}[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

}

                                 6.1.3 直接插入排序 算法分析:

关键字比较次数和记录移动次数与记录关键字的初始排列有关。

最好情况下, 排序前记录已按关键字从小到大有序, 每趟只需与前面有序 记录序列的最后一个记录比较1次, 移动2次记录, 总的关键字比较次数 为 n-1, 记录移动次数为 2(n-1)在平均情况下的关键字比较次数和记录 移动次数约为n2/4 。

直接插入排序是一种稳定的排序方法

直接插入排序最大的优点是简单,在记录数较少时,是比较好的办法

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                                   6.1.4 希尔排序 希尔排序又称缩小增量排序

是1959年由D.L.Shell提出来的

算法描述

先取定一个小于n的整数d作为第一个增量,把表的全部记录分成d组 所有距离为d1的倍数的记录放在同一组中,在各组内进行直接插入

排序 然后取第二个增量d2<d1

重复上述的分组和排序,直至增量d=1,即所有记录放在同一组中 进行直接插入排序为止。

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                                   6.1.4 希尔排序

算法特点

先取定一个小于n的整数d作为第一个增量,把表的全部记录分成d组 所有距离为d1的倍数的记录放在同一组中,在各组内进行直接插入

排序 然后取第二个增量d2<d1

重复上述的分组和排序,直至增量d=1,即所有记录放在同一组中 进行直接插入排序为止。

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                                   6.1.4 希尔排序

运用实例

先取定一个小于n的整数d作为第一个增量,把表的全部记录分成d组 所有距离为d1的倍数的记录放在同一组中,在各组内进行直接插入

排序 然后取第二个增量d2<d1

重复上述的分组和排序,直至增量d=1,即所有记录放在同一组中 进行直接插入排序为止。

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                             6.1.4 希尔排序 算法描述

首先取一个整数 gap < n(待排序记录数) 作为间隔, 将全部记录分为 gap 个子序列, 所有距离为 gap 的记录放在同一个子序列中

在每一个子序列中分别施行直接插入排序。 然后缩小间隔 gap, 例如取 gap = gap/2

重复上述的子序列划分和排序工作,直到最后取gap = 1, 将所有记录放在同 一个序列中排序为止。

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                       6.1.4 希尔排序 运用实例

已知待排序的一组记录的初始排列为:21, 25, 49, 25*, 16, 08

012345

21254925*1608

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                                                     6.1.4 希尔排序 运用实例

012345

T= 3

21254925*1608012345

T= 2

21160825*254908162125*2549

T= 1

08162125*2549[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

21160825*2549

08162125*2549[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                           6.1.4 希尔排序 算法分析

开始时 gap 的值较大, 子序列中的记录较少, 排序速度较快

随着排序进展, gap 值逐渐变小, 子序列中记录个数逐渐变多,由于 前面大多数记录已基本有序, 所以排序速度仍然很快

Gap的取法有多种。 shell 提出取 gap = ?n/2?,gap = ?gap/2?, 直到gap = 1。

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                                          6.1.5 选择排序

排序过程:

首先通过n-1次比较,从n个数中找出最小的, 将它与第一个数 交换—第一趟选择排序,结果最小的数被安置在第一个元素位

置上 再通过n-2次比较,从剩余的n-1个数中找出关键字次小的记录,

将它与第二个数交换—第二趟选择排序 重复上述过程,共经过n-1趟排序后,排序结束

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                                           6.1.5 选择排序

k

k

k

初始: [49 i=1 13

38

65

97

76

13 27] 49

排序实例:

jjjjjj

i=2

一趟: 13 二趟: 13

[38 65 97 76 49 3287] 27

三趟: 13 四趟: 13

27[6597764938] 2738[97764965]

k

k

j

jj

j

j

273849[769765] 27384965[9776]

五趟: 13

[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

六趟: 13 27 38 49 65 76 [97] [email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                                           6.1.5 选择排序 算法实例:

初始 214925

25*16

16 08

i=1i =2

21

25

4925*49

16

0821

012345

i 0825

i =349

49 25*[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

i 49

1625*25

21上海嵌入式08-开发板商城 http://embedclub.taobao.com/

16

08

                             6.1.5 选择排序 算法实例:

25* 25012345

最小者 25*无交换

08

16

21

08

16

21

25*25

最小者 2549无交换

49[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

21

25*25

16

[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

08

各趟排序后的结果

                                              6.1.5 选择排序 算法实例:

i =2时选择排序的过程

2549012345

08

ikj

25*4925

16

21

08

16

2549ikj

49

[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

2525*

16

21

08

[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

ikj

16<25

25*

2125*25

                             6.1.5 选择排序 算法实例:

2549012345

08

16

21

2116

25*ikj

k指示当前序列中最小者

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                             6.1.5 选择排序 算法实现:

#include <stdio.h> main()

输入n 个数给a[1] 到 a[n] for i=1 to n-1

scanf("%d",&a[i]);

i!=k 输出a[1] 到 a[n]

假 if(i!=k)

{ x=a[i]; a[i]=a[k]; a[k]=x;}

a[j]<a[k]

{ k=i;

k=i

for j=i+1 to n

printf("\n");

k=j

假 for(j=i+1;j<=10;j++) if(a[j]<a[k]) k=j;

a[i]⇔a[k]

{

int a[11],i,j,k,x;

printf("Input 10 numbers:\n"); for(i=1;i<11;i++)

for(i=1;i<10;i++)

}

printf("The sorted numbers:\n");

for(i=1;i<11;i++)

[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

printf("%d ",a[i]);

[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git}

各种排序算法对比分析

排序法

平均时间

最差情形 稳定度 额外空间

备注 n小时较好 n小时较好 n小时较好

冒泡

O(n2) O(n2) O(n2) O(n2)

O(n2) 稳定 O(n2) 不稳定 O(n2) 不稳定

O(1) O(1) O(1) O(1)

交换

选择

插入 时较好

O(n2) 稳定 O(logRB) 稳定

O(ns) 1<s<2 不稳定

大部分已排序

基数 (个十百)

O(logRB)

O(n)

B是真数(0-9),R

Shell

O(nlogn) O(nlogn) O(nlogn) O(nlogn)

O(1) s是所选分组 O(n2) 不稳定 O(nlogn) n大时较好

快速 归并 堆

O(nlogn) 稳定 O(1) n大时较好 O(nlogn) 不稳定 O(1) n大时较好

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

阶段小节

几种常见的排序算法

冒泡排序的特点

快速排序的特点,一趟排序的子过程

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

本章总结

数据结构与算法初步

数据结构与算法初步

常见的排序算法

常见的排序算法

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

重点讲述冒泡排序和快速排序的特,

同时大概了解直接插入排序,希尔排

序和选择排序的基本思路

实验1 题目

题目:实现对数组{265,301,751,129,937,863,742,694,076,438} 进行排序,用快速排序方法来实现。并列出每趟排序的结果

实验目的

考察快速排序算法的基本思路

了解快速排序算法的每趟操作流程

实验分析

建立一个数组,并初始化

进行数据的第一趟快速排序

了解快速排序每趟操作结果,分析排序快速的最快数组类型和最慢数组类型

[email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

时间: 2025-01-02 14:31:48

第六章 常见排序算法的相关文章

【整理】常见排序算法及其时间复杂度总结

原文出处: 1. 白话经典算法系列之八 MoreWindows白话经典算法之七大排序总结篇 2. 面试常用算法总结--排序算法(java版) 3. 常见排序算法小结 本篇主要整理了冒泡排序,直接插入排序,直接选择排序,希尔排序,归并排序,快速排序,堆排序七种常见算法,是从上面三篇博文中摘抄整理的,非原创. 一.冒泡排序 主要思路是: 通过交换相邻的两个数变成小数在前大数在后,这样每次遍历后,最大的数就"沉"到最后面了.重复N次即可以使数组有序. 冒泡排序改进1: 在某次遍历中,如果没有

JavaScript版几种常见排序算法

今天发现一篇文章讲“JavaScript版几种常见排序算法”,看着不错,推荐一下原文:http://www.w3cfuns.com/blog-5456021-5404137.html 算法描述: * 冒泡排序:最简单,也最慢,貌似长度小于7最优* 插入排序: 比冒泡快,比快速排序和希尔排序慢,较小数据有优势* 快速排序:这是一个非常快的排序方式,V8的sort方法就使用快速排序和插入排序的结合* 希尔排序:在非chrome下数组长度小于1000,希尔排序比快速更快* 系统方法:在forfox下系

常见排序算法(一) MergeSort

算法思想灰常重要,常见的用到分治思想的算法包括快速排序,归并,二分搜搜,大整数乘法等(参考 http://blog.csdn.net/com_stu_zhang/article/details/7233761,归纳很到位) 简单用归并对一个数组排序 思路: 简单来说对一个数组,只要他的左右两部分都是有序的,那么简单合并就ok了,那么左右两部分可以进一步划分各自的左右两部分----明显就是要递归了 算法:归并排序 1. 将数组一分为二,subArray1 和subArray2 2. 归并排序sub

常见排序算法(java实现)

常见排序算法介绍 冒泡排序 代码: public class BubbleSort { public static void sort(int[] array) { int tValue; for (int i = 0; i < array.length; i++) { for (int j = i; j < array.length; j++) { if (array[i] > array[j]) { tValue = array[i]; array[i] = array[j]; ar

常见排序算法(冒泡、选择、插入、快速、归并C++实现)

常见排序算法(冒泡.选择.插入.快速.归并C++实现) #include <iostream> using namespace std; // 冒泡排序 void bubbleSort (int data[], size_t size) { for (size_t i = 0; i < size - 1; ++i) { bool ordered = true; for (size_t j = 0; j < size - 1 - i; ++j) if (data[j+1] <

[读书笔记]算法(Sedgewick著)·第二章.初级排序算法

本章开始学习排序算法 1.初级排序算法 先从选择排序和插入排序这两个简单的算法开始学习排序算法.选择排序就是依次找到当前数组中最小的元素,将其和第一个元素交换位置,直到整个数组有序. 1 public static void sort(Comparable a[]){ 2 int N = a.length; 3 for(int i = 0; i < N; i ++){ 4 int min = i; //最小元素索引 5 for(int j = i + 1; j < N; j++){ 6 if(

几种常见排序算法

几种常见排序算法 几种常见排序算法 写在前面 基础介绍 初级排序算法 selection sort选择排序 insertion sort插入排序 ShellSort希尔排序 shuffing不是排序算法 merge sort归并排序 Abstract in-place merge原地归并的抽象方法 Top-down mergesort自顶向下的归并排序 Bottom-up mergesort自底向上的归并排序 quicksort 三向切分的快速排序 Heapsort堆排序 总结和比较 命题 本文

常见排序算法总结(java实现)

所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作.常见的排序算法有选择排序,插入排序,希尔排序,归并排序和快速排序 由于在排序的过程中不可避免的要涉及到比较和交换,所以将他们抽取为两个单独的函数,如下所示 //为了排序代码的通用性,这里假定待排序的元素实现了Comparable接口 private static boolean less(Comparable v ,Comparable w){ return v.compareTo(w)<0; } priva

十种常见排序算法

1.常见算法分类 十种常见排序算法一般分为以下几种: (1)非线性时间比较类排序:交换类排序(快速排序和冒泡排序).插入类排序(简单插入排序和希尔排序).选择类排序(简单选择排序和堆排序).归并排序(二路归并排序和多路归并排序): (2)线性时间非比较类排序:计数排序.基数排序和桶排序. 总结: (1)在比较类排序中,归并排序号称最快,其次是快速排序和堆排序,两者不相伯仲,但是有一点需要注意,数据初始排序状态对堆排序不会产生太大的影响,而快速排序却恰恰相反. (2)线性时间非比较类排序一般要优于