@

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)
  • 稳定性:在划分算法中,若右端区间有两个关键字相同,且均小于基准值的记录,则在交换到左侧区间后,它们的相对位置发生了变化,即快速排序是一种不稳定的排序方法。
  • 快速排序是所有排序内部排序算法中平均性能最优的排序算法。

【注】:在快速排序算法中,并不产生有序子序列,但每趟排序后会将枢轴(基准)元素放到其最终的位置上。

3. 选择排序

选择排序的基本思想是:每一趟(第i趟)在后面的n-i+1(i=1,2,,...,n-1)个待排序元素中选取关键字最小的元素,作为有序子序列的第i个元素,直到n-1趟做完,待排序元素只剩下一个,就不用再选了。

3.1 简单选择排序

简单选择排序算法思想:假设排序表为L[1,n],第i趟排序即从L[i,n]中选取关键字最小的元素与L(i)交换,每一趟排序可以确定一个元素的最终位置,这样经过n-1趟排序就可以使得整个排序表有序



参考代码如下:

void SelectSort(int A[],int n){
int i,j,min_index,temp;
for(i=0;i<n-1;i++){
min_index = i;
for(j=i+1;j<n;j++){
if(A[j]<A[min_index]){
min_index = j;
}
}
if(min_index!=i){
temp = A[i];
A[i] = A[min_index];
A[min_index] = temp;
}
}
}
  • 空间复杂度:O(1)
  • 时间复杂度:O(n^2)
  • 稳定性:简单选择排序是一种不稳定的排序方法
  • 使用性:既可以用于顺序表,也可以用于链表
  • 比较次数:n(n-1)/2

3.2 堆排序

堆定义如下:n个关键字序列L[1,n]称为堆,当且仅当该序列满足:

(1)L[i]>L[2i]且L[i]>L[2i+1]或

(2)L[i]<L[2i]且L[i]<L[2i+1]

可以将该一维数组称为一棵完全二叉树,满足条件(1)的堆称为大根堆(大顶堆),大根堆的最大元素存放在根节点,且其任一非根节点的值小于等于其双亲节点值。满足条件(2)的堆称为小根堆(小顶堆),根节点是最小元素。

  • 利用大根堆进行排序得到的序列为升序序列
  • 利用小根堆进行排序得到的序列为降序序列

3.2.1 大根堆

建立大根堆的算法如下:

void BuildMaxHeap(int A[],int len);
int main(){
int A[] = {0,53,17,78,9,45,65,87,32};
printf("初始序列:\n");
for(int i=1;i<=8;i++){
printf("%d\t",A[i]);
}
printf("\n");
BuildMaxHeap(A,8);
printf("大根堆:\n");
for(int i=1;i<=8;i++){
printf("%d\t",A[i]);
}
printf("\n");
return 0;
} void HeadAdjust(int A[],int k,int len){
A[0] = A[k]; // A[0]暂存子树的根节点
int i;
for(i=2*k;i<=len;i*=2){
if(i<len&&A[i]<A[i+1])
i++;
// 取key较大的子节点的下标
if(A[0]>=A[i]) break;
else{
A[k] = A[i]; // 将A[i]调整到双亲节点上
k = i; // 修改k值,以便继续向下筛选
}
}
A[k] = A[0];
} void BuildMaxHeap(int A[],int len){
for(int i=len/2;i>0;i--){
HeadAdjust(A,i,len);
}
}

运行结果:



推排序算法如下:

void HeapSort(int A[],int len){
BuildMaxHeap(A,len);
int i,temp;
for(i=len;i>1;i--){
temp = A[1];
A[1] = A[i];
A[i] = temp;
HeadAdjust(A,1,i-1);
}
}

运行结果:

3.2.2 小根堆

建立小根堆的算法如下:

void HeadAdjust2(int A[],int k,int len){
A[0] = A[k];
int i;
for(i=2*k;i<=len;i*=2){
if(i<len&&A[i]>A[i+1])
i++;
// 取key较小的子节点下标
if(A[0]<=A[i])
break;
else{
A[k] = A[i];
k = i;
}
}
A[k] = A[0];
} void BuildMinHeap(int A[],int len){
for(int i=len/2;i>0;i--){
HeadAdjust2(A,i,len);
}
}

运行结果:



堆排序算法如下:

void HeapSort2(int A[],int len){
BuildMinHeap(A,len);
int i,temp;
for(i=len;i>1;i--){
temp = A[1];
A[1] = A[i];
A[i] = temp;
HeadAdjust2(A,1,i-1);
}
}

运行结果:

  • 空间复杂度:O(1)
  • 时间复杂度:O(nlogn)
  • 稳定性:堆排序算法是一种不稳定排序方法

数据结构(C语言版)严蔚敏->排序的更多相关文章

  1. 《数据结构-C语言版》(严蔚敏,吴伟民版)课本源码+习题集解析使用说明

    <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明 先附上文档归类目录: 课本源码合辑  链接☛☛☛ <数据结构>课本源码合辑 习题集全解析  链接☛☛☛  ...

  2. 数据结构C语言版 表插入排序 静态表

    数据结构C语言版 表插入排序.txt两个人吵架,先说对不起的人,并不是认输了,并不是原谅了.他只是比对方更珍惜这份感情./*  数据结构C语言版 表插入排序  算法10.3 P267-P270  编译 ...

  3. c++学习书籍推荐《清华大学计算机系列教材:数据结构(C++语言版)(第3版)》下载

    百度云及其他网盘下载地址:点我 编辑推荐 <清华大学计算机系列教材:数据结构(C++语言版)(第3版)>习题解析涵盖验证型.拓展型.反思型.实践型和研究型习题,总计290余道大题.525道 ...

  4. 数据结构C语言版 有向图的十字链表存储表示和实现

    /*1wangxiaobo@163.com 数据结构C语言版 有向图的十字链表存储表示和实现 P165 编译环境:Dev-C++ 4.9.9.2 */ #include <stdio.h> ...

  5. 数据结构C语言版 弗洛伊德算法实现

    /* 数据结构C语言版 弗洛伊德算法  P191 编译环境:Dev-C++ 4.9.9.2 */ #include <stdio.h>#include <limits.h> # ...

  6. 【数据结构(C语言版)系列二】 栈

    栈和队列是两种重要的线性结构.从数据结构角度看,栈和队列也是线性表,但它们是操作受限的线性表,因此,可称为限定性的数据结构.但从数据类型角度看,它们是和线性表大不相同的两类重要的抽象数据类型. 栈的定 ...

  7. 【数据结构(C语言版)系列三】 队列

    队列的定义 队列是一种先进先出的线性表,它只允许在表的一端进行插入,而在另一端删除元素.这和我们日常生活中的排队是一致的,最早进入队列的元素最早离开.在队列中,允许插入的一端叫做队尾(rear),允许 ...

  8. 深入浅出数据结构C语言版(17)——有关排序算法的分析

    这一篇博文我们将讨论一些与排序算法有关的定理,这些定理将解释插入排序博文中提出的疑问(为什么冒泡排序与插入排序总是执行同样数量的交换操作,而选择排序不一定),同时为讲述高级排序算法做铺垫(高级排序为什 ...

  9. 深入浅出数据结构C语言版(17)——希尔排序

    在上一篇博文中我们提到:要令排序算法的时间复杂度低于O(n2),必须令算法执行"远距离的元素交换",使得平均每次交换减少不止1逆序数. 而希尔排序就是"简单地" ...

随机推荐

  1. Web安全学习笔记 SQL注入下

    Web安全学习笔记 SQL注入下 繁枝插云欣 --ICML8 SQL注入小技巧 CheatSheet 预编译 参考文章 一点心得 一.SQL注入小技巧 1. 宽字节注入 一般程序员用gbk编码做开发的 ...

  2. 论文解读《Deep Attention-guided Graph Clustering with Dual Self-supervision》

    论文信息 论文标题:Deep Attention-guided Graph Clustering with Dual Self-supervision论文作者:Zhihao Peng, Hui Liu ...

  3. 645. Set Mismatch - LeetCode

    Question 645. Set Mismatch Solution 思路: 遍历每个数字,然后将其应该出现的位置上的数字变为其相反数,这样如果我们再变为其相反数之前已经成负数了,说明该数字是重复数 ...

  4. layui数据表格搜索

    简单介绍 我是通过Servlet传递json给layui数据表格模块,实现遍历操作的,不过数据量大的话还是需要搜索功能的.这是我参考网上大佬代码写出的搜索功能. 实现原理 要实现搜索功能,肯定需要链接 ...

  5. GoF的23种设计模式的功能

    GoF的23种设计模式的功能 前面说明了 GoF 的 23 种设计模式的分类,现在对各个模式的功能进行介绍. 单例(Singleton)模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取 ...

  6. 如何在 pyqt 中捕获并处理 Alt+F4 快捷键

    前言 如果在 Windows 系统的任意一个窗口中按下 Alt+F4,默认行为是关闭窗口(或者最小化到托盘).对于使用了亚克力效果的窗口,使用 Alt+F4 最小化到托盘,再次弹出窗口的时候可能出现亚 ...

  7. vue组件传参的方法--bus事件总线

    定义:事件总线是实现vue任意组件之前传递参数的一种编程技巧,本质上就是组件的自定义事件.事件总线有很多种写法,具体的思路就是创造一个大家都可以访问到的公共的属性,在这个公共的属性上面可以调用$on, ...

  8. MySQL - 锁的分类

    MySQL - 锁的分类 1. 加锁机制 乐观锁 悲观锁 2. 兼容性 共享锁 排他锁 3. 锁粒度 表锁 页锁 行锁 4. 锁模式 记录锁(record-lock) 间隙锁(gap-lock) ne ...

  9. CentOS8安装mysql8.0具体步骤

    操作系统:CentOS Linux release 8.0及以上 Mysql版本:Mysql 8.0.22 x86_64 (MySQL Community Server - GPL) Mysql8下载 ...

  10. 聊聊消息中间件(1),AMQP那些事儿

    开篇 说到消息队列,相信大家并不陌生.大家在日常的工作中其实都有用过.相信大部分的研发在使用消息队列的过程中也仅仅是停留在用上面,里面的知识点掌握得并不是很系统,有部分强大的功能可能由于本身公司的业务 ...