数据结构(C语言版)严蔚敏->排序
Posted il_持之以恒_li
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构(C语言版)严蔚敏->排序相关的知识,希望对你有一定的参考价值。
排序
1. 插入排序
插入排序是一种简单直观的排序方法,其基本思想是每次将一个待排序的记录按其关键字大小插入前面已排好序的子序列,直到全部记录插入完全。
1.1 直接插入排序
直接插入排序运行动态图如下:
参考代码如下:
#include <stdio.h>
void InsertSort(int[],int);
// 无哨兵的插入排序
void PrintData(int[],int);
void InsertSort2(int[],int);
// 有哨兵的插入排序,数组下标为0处不存储数据元素
void PrintData2(int[],int);
int main()
int A1[] = 49,38,65,97,76,13,27,49;
InsertSort(A1,8);
PrintData(A1,8);
printf("\\n");
int A2[] = 0,49,38,65,97,76,13,27,49;
InsertSort2(A2,8);
PrintData2(A2,8);
return 0;
void InsertSort(int A[],int n)
int i,j,temp;
for(i=1;i<n;i++)
if(A[i]<A[i-1])
temp = A[i];
for(j=i-1;j>=0&&temp<A[j];--j)
A[j+1] = A[j];
A[j+1] = temp;
void InsertSort2(int A[],int n)
int i,j;
for(i=2;i<=n;i++)
if(A[i]<A[i-1])
A[0] = A[i];
for(j=i-1;A[0]<A[j];--j)
A[j+1] = A[j];
A[j+1] = A[0];
void PrintData(int A[],int n)
for(int i=0;i<n;i++)
printf("%d\\t",A[i]);
void PrintData2(int A[],int n)
for(int i=1;i<=n;i++)
printf("%d\\t",A[i]);
运行结果如下:
- 算法的空间复杂度:O(1)
- 算法的时间复杂度:O(n^2)
- 稳定性:由于每次插入元素时总是从后向前比较再移动,所以不会出现相同元素相对位置发生变化的情况,即直接插入是一种稳定的排序算法。
1.2 折半插入排序
参考代码如下:
void InsertSort3(int A[],int n)
int i,j,low,high,mid;
for(i=2;i<=n;i++)
A[0] = A[i];
low = 1,high = i-1;
while(low<=high)
mid = (low+high)/2;
if(A[mid] > A[0])
high = mid - 1;
else
low = mid + 1;
for(j=i-1;j>=high+1;--j)
A[j+1] = A[j];
A[high+1] = A[0];
- 算法时间复杂度:折半插入排序的时间复杂度为O(n^2),但对于数据量不是很大的排序表,折半插入排序往往能表现出很好的性能。
1.3 希尔排序(Shell Sort)
希尔排序的基本思想是:先将待排序表分成L[i,i+d,i+2d,…,i+kd]的“特殊”子表,即把相隔某个“增量”的记录组成一个子表,对各个子表分别进行直接插入排序,当整个表中的元素已呈“基本有序”时,再对全体记录进行一次直接插入排序。
参考代码如下:
void ShellSort(int A[],int n)
// 希尔排序
int i,j,dk;
for(dk=n/2;dk>=1;dk/=2)
// 步长变化
for(i=dk+1;i<=n;i++)
if(A[i] < A[i-dk])
A[0] = A[i];
// A[0]元素只是暂存元素,不是哨兵
for(j=i-dk;j>0&&A[j]>A[0];j-=dk)
A[j+dk] = A[j]; // 记录后移,查找插入的位置
A[j+dk] = A[0]; // 插入
- 算法的空间复杂度:O(1)
- 算法的时间复杂度:希尔排序的时间复杂度约为O(n^1.3),在最坏情况下希尔排序的时间复杂度为O(n^2).
- 稳定性:当相同关键字的记录被划分到不同的子表时,可能会改变它们之间的相对次序,因此希尔排序是一种不稳定的排序方法。
2.交换排序
2.1 冒泡排序
基本思想:从后往前(或从前往后)两两比较相邻元素的值,若为逆序(即A[i-1]>A[i]),则交换它们,直到序列比较完毕!
下图为一个冒泡排序的过程(从后往前两两比较相邻元素的值【即先把小的元素往前排】)。
到了第五趟结束后没有发生交换,说明表已经有序。
下图为另外一个冒泡排序的过程(从前往后两两比较相邻元素的值【即先把大的元素往后排】)
参考代码如下:
// 冒泡排序
void BubbleSort(int A[],int n)
int i,j,temp;
bool flag;
for(i=0;i<n-1;i++)
flag = false;
for(j=n-1;j>i;j--)
if(A[j-1]>A[j])
temp = A[j-1];
A[j-1] = A[j];
A[j] = temp;
flag = true;
if(!flag)
return;
// 某一趟遍历后没有发生交换,说明表已经有序
- 算法的空间复杂度:O(1)
- 算法的时间复杂度:O(n^2)
- 算法的稳定性:由于i>j且A[i]=A[j]时,不会发生交换,因此冒泡排序是一种稳定的排序方法。
- 比较次数:n(n-1)/2
- 移动次数:3n(n-1)/2
2.2 快速排序
基本思想:在待排序表L[1,n]中任取一个元素pivot作为枢轴(或基准,通常取首元素),通过一趟排序将待排序表划分为独立的两部分L[1,k-1]和L[k+1,n],使得L[1,k-1]中的所有元素小于pivot,L[k+1,n]中的所有元素大于等于pivot,则pivot放在了最终位置L(k)上,这个过程称为一趟快速排序。然后分别递归地对两个子表重复上述过程,直至每部分内只有一个元素为止,即所有元素放在了其最终的位置上。
快速排序过程如下:
参考代码如下:
int Partition(int A[],int low,int high)
int pivot = A[low];
while(low<high)
while(low<high&&A[high]>=pivot)
high--;
A[low] = A[high];
while(low<high&&A[low]<=pivot)
low++;
A[high] = A[low];
A[low] = pivot;
return low;
void QuickSort(int A[],int low,int high)
if(low<high)
int pivotpos = Partition(A,low,high);
QuickSort(A,low,pivotpos-1);
QuickSort(A,pivotpos+1,high);
- 空间复杂度:最好情况下为O(logn),最坏情况下为O(n)
- 时间复杂度:最好为O(nlogn),最坏为O(n^2),平均情况下为O(nlogn)
- 稳定性:在划分算法中,若右端区间有两个关键字相同,且均小于基准值的记录,则在交换到左侧区间后,它们的相对位置发生了变化,即快速排序是一种不稳定的排序方法。
- 快速排序是所有排序内部排序算法中平均性能最优的排序算法。
【注】:在快速排序算法中,并不产生有序子序列,但每趟排序后会将枢轴(基准)元素放到其最终的位置上。
以上是关于数据结构(C语言版)严蔚敏->排序的主要内容,如果未能解决你的问题,请参考以下文章
10-7-快速排序-内部排序-第10章-《数据结构》课本源码-严蔚敏吴伟民版
10-6-起泡排序-内部排序-第10章-《数据结构》课本源码-严蔚敏吴伟民版
10-5-希尔排序-内部排序-第10章-《数据结构》课本源码-严蔚敏吴伟民版