交换排序--冒泡排序和快速排序

交换,是指根据序列中两个元素关键字的比较结果来对换这两个记录在序列中的位置

一,冒泡排序

1.基本思想:从后往前(或从前往后)两两比较相邻元素的值,若为逆序(A[i-1] > A[i]),则交换它们,直到序列比较完

2.过程

数组序号01234567
待排序元素49

38

659776132749
49和27比较4938659776132749
27和13比较4938659776132749
13和76比较4938659713762749
13和97比较4938651397762749
13和65比较4938136597762749
13和38比较4913386597762749
13和49比较1349386597762749

冒泡排序中所产生的有序子序列一定是全局有序的(不同于直接插入排序),也就是说,有序子序列中的所有元素的关键字一定小于(或大于)无序子序列中所有元素的关键字,这样每趟排序都会将一个元素放置到最终的位置上

3.代码展示

//冒泡排序
void BubbleSort(Str &L)
{for(int i = 0; i < L.length-1; ++i)//i表示的是i前面有几个已经确定好最终位置的元素{bool flag = false;//表示本次冒泡是否发生交换的标志for(int j = L.length-1; j > i; --j)//从待排序列最后一个元素依次向前进行比较,已经排好的元素无需再比较,所以是j > i{if(L.data[j] < L.data[j-1])//元素是从小到大的顺序进行排序{swap(L.data[j],L.data[j-1]);//交换位置flag = true;//表示这趟冒泡过程发生了交换}	}if(flag == false)//如果没有发生交换,就表示待排序列已经排序好了,直接结束程序return;}
}

4.结果:

 

 

二,快速排序

1.基本思想:在待排序表L[1....n]中任取一个元素pivot作为枢轴(或称基准,通常取首元素),通过排序将排序表分为两部分,L[1...k-1]中元素小于pivot,L[k+1...n]元素大于等于pivot,最后将pivot元素放到L[k]中,直到所有元素全部放到最终位置。

2.过程

2.1,将序号low元素作为枢轴放到pivot中

数组序号01234567
待排序列4938659776132749
lowhigh

2.2,此时序号low中的元素已经被赋值到其他变量中,所以此时序号low可以被赋值其他值,所以要从high开始访问。因为49>=49,所以high = high-1 = 6; 27<49,所以将27赋值到序号low处。

数组序号01234567
待排序列2738659776132749
lowhigh

2.3,此时原本序号6中的元素以及被赋值到0处,所以序号6处的元素可以被覆盖,所以从low开始进行访问。27<49,low = low+1 = 1;  38<49,low = low+1 = 2; 65>49,所以将65赋值到high处

数组序号01234567
待排序列2738659776136549
lowhigh

2.4,同理,65>49, high = high-1 = 5; 13<49,将13赋值到low处。

数组序号01234567
待排序列2738139776136549
lowhigh

2.5,同理,13<49,low = low+1 = 3; 97>49,所以将97赋值到high处

数组序号01234567
待排序列2738139776976549
lowhigh

2.6,同理,97>49,high = high-1 = 4; 76>49, high = high-1 = 3; 此时high = low = 3,所以将49赋值到low处

数组序号01234567
待排序列2738134976976549

low

high

在快速排序算法中,并不产生有序子序列,但每趟排序之后会将上一趟划分的各个无序子表的枢轴(基准)元素放到其最终的位置上

408原题中说,对所有尚未确定最终位置的所有元素进行一遍处理称为“一趟”排序,因此依次“划分”!= “一趟排序”。一次划分可以确定一个元素最终的位置,二一趟排序也许可以确定多个元素的最终位置

3.代码展示

//快速排序
void QuickSort(Str &L,int low, int high)
{//类似于二叉树,进行递归if(low < high){int pivotpos = Partition(L,low,high);//划分操作,以low所在序号元素作为枢轴元素,将待排序列划分成左边是比枢轴元素小,右边比枢轴元素大QuickSort(L,low,pivotpos-1);//依次对两个子表进行划分,进行递归QuickSort(L,pivotpos+1,high);}
}int Partition(Str &L,int low, int high)
{int pivot = L.data[low];//将low所在序号元素作为枢轴,暂存在pivot里面,以免被覆盖while(low < high)//循环条件{while(low < high && L.data[high] >= pivot)//最开始已经将序号为low的数组元素已经赋值给其他变量中,所以现在low序号的元素可以被覆盖,所以是从high那边开始high--;//如果L.data[high] > pivot,就符合要求,这就检查前面那个元素,所以high--;L.data[low] = L.data[high];//如果不满足条件low < high,那就是high = low,此时L.data[low] = L.data[high],不会有影响;如果L.data[high] < pivot,那就将元素赋值到序号low中while(low < high && L.data[low] < pivot)//如果满足条件那么就向后面一个元素进行访问low++;L.data[high] = L.data[low];//如果不满足条件,这个1时候序号high所在数组元素已经赋值给其他地方,此时覆盖不会造成元素丢失}L.data[low] = pivot;//结束循环,找到枢轴所在位置,将pivot中元素赋值到该位置,就可以达到左边比其小,右边比其大return low;//返回存放枢轴的最终位置
}

 4.结果

 三,总结

交换排序空间复杂度时间复杂度稳定性
冒泡排序O(1)O(n^{2})稳定
快速排序O(递归层数)O(n*递归层数)不稳定

 

最好情况:若每一次选中的枢轴将待排序列划分成均匀的两个部分,则递归深度最小,算法效率最高。类似于二叉树,n个结点的二叉树最小高度 = \log n+1

空间复杂度最好情况为:O(\log n); 时间复杂度最好情况为:O(n \log n)

最坏情况:n个结点二叉树最大高度为n

空间复杂度最坏情况为:O(n); 时间复杂度最坏情况为:O(n^{2})

一般情况下,最坏的情况几率比较小,所以快速排序平均时间复杂度为O(n \log n)

快速排序是所有内部排序算法中平均性能最优的排序算法

交换排序元素是否被放在最终位置上
冒泡排序产生的有序子序列一定是全局有序的(不同于直接插入排序),也就是说,有序子序列中的所有元素的关键字一定小于(或大于)无序子序列中所有元素的关键字,这样每趟排序都会将一个元素放置到最终的位置上
快速排序在快速排序算法中,并不产生有序子序列,但每趟排序之后会将上一趟划分的各个无序子表的枢轴(基准)元素放到其最终的位置上

四,完整代码

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#define Maxsize 8
//数组结构体
typedef struct
{int *data;int length;
}Str;//函数说明
void CreatString(Str &L);
void swap(int &a, int &b);
void BubbleSort(Str &L);
void PrintStr(Str L);
void QuickSort(Str &L,int low, int high);
int Partition(Str &L,int low, int high);int main(void)
{Str L;CreatString(L);BubbleSort(L);printf("冒泡排序之后数组元素为:\n");PrintStr(L);Str L1;CreatString(L1);QuickSort(L1,0,7);printf("快速排序之后数组元素为:\n");PrintStr(L1);return 0;
}//创造数组
void CreatString(Str &L)
{L.data = (int *)malloc(sizeof(int)*Maxsize);L.length = Maxsize;int val;for(int i = 0; i < L.length; ++i){printf("输入数组第%d个元素的值:",i+1);scanf_s("%d",&val);L.data[i] = val;}
}//交换函数
void swap(int &a, int &b)
{int temp = a;a = b;b = temp;
}//冒泡排序
void BubbleSort(Str &L)
{for(int i = 0; i < L.length-1; ++i)//i表示的是i前面有几个已经确定好最终位置的元素{bool flag = false;//表示本次冒泡是否发生交换的标志for(int j = L.length-1; j > i; --j)//从待排序列最后一个元素依次向前进行比较,已经排好的元素无需再比较,所以是j > i{if(L.data[j] < L.data[j-1])//元素是从小到大的顺序进行排序{swap(L.data[j],L.data[j-1]);//交换位置flag = true;//表示这趟冒泡过程发生了交换}	}if(flag == false)//如果没有发生交换,就表示待排序列已经排序好了,直接结束程序return;}
}//遍历输出
void PrintStr(Str L)
{for(int i = 0; i < L.length; ++i){printf("%d ",L.data[i]);}printf("\n");
}//快速排序
void QuickSort(Str &L,int low, int high)
{//类似于二叉树,进行递归if(low < high){int pivotpos = Partition(L,low,high);//划分操作,以low所在序号元素作为枢轴元素,将待排序列划分成左边是比枢轴元素小,右边比枢轴元素大QuickSort(L,low,pivotpos-1);//依次对两个子表进行划分,进行递归QuickSort(L,pivotpos+1,high);}
}int Partition(Str &L,int low, int high)
{int pivot = L.data[low];//将low所在序号元素作为枢轴,暂存在pivot里面,以免被覆盖while(low < high)//循环条件{while(low < high && L.data[high] >= pivot)//最开始已经将序号为low的数组元素已经赋值给其他变量中,所以现在low序号的元素可以被覆盖,所以是从high那边开始high--;//如果L.data[high] > pivot,就符合要求,这就检查前面那个元素,所以high--;L.data[low] = L.data[high];//如果不满足条件low < high,那就是high = low,此时L.data[low] = L.data[high],不会有影响;如果L.data[high] < pivot,那就将元素赋值到序号low中while(low < high && L.data[low] < pivot)//如果满足条件那么就向后面一个元素进行访问low++;L.data[high] = L.data[low];//如果不满足条件,这个1时候序号high所在数组元素已经赋值给其他地方,此时覆盖不会造成元素丢失}L.data[low] = pivot;//结束循环,找到枢轴所在位置,将pivot中元素赋值到该位置,就可以达到左边比其小,右边比其大return low;//返回存放枢轴的最终位置
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/9061.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【MYSQL基础】基础命令介绍

基础命令 MYSQL注释方式 -- 单行注释/* 多行注释 哈哈哈哈哈 哈哈哈哈 */连接数据库 mysql -u root -p12345678退出数据库连接 使用exit;命令可以退出连接 查询MYSQL版本 mysql> select version(); ----------- | version() | ----------- | 8.0.27 | ----------- 1…

ASP.Net Core Web API项目发布到IIS(二)

目录 一.启动并配置IIS环境 1.启用或关闭window功能 2.设置万维网服务 3.点击确定等待配置更改 二.创建新的Web网站并进行设置 1.打开IIS管理 2.配置默认的网站 3.创建新的网站 4.测试 三.可能出现的问题 1.404错误 前一篇已经记录了如何创建项目并发布到文件夹&#x…

【MySQL系列】在Centos7环境安装MySQL

「前言」文章内容大致是在Centos7环境安装MySQL&#xff0c;演示安装的版本为5.7 「归属专栏」MySQL 「笔者」枫叶先生(fy) 「座右铭」前行路上修真我 「枫叶先生有点文青病」「句子分享」 浮生梦&#xff0c;三生渺渺&#xff0c; 因缘无踪&#xff0c;虽堪恋&#xff0c…

C++动态内存管理

文章目录 &#x1f428;0. 前言&#x1f98d;1. C/C内存分布&#x1f988;2. C内存管理&#x1f41a;2.1 new和delete操作内置类型&#x1f41a;2.2 new和delete操作自定义类型 &#x1f9ad;3. new和delete底层&#x1f5ff;3.1 operator new和operator delete函数&#x1f5f…

2021年国赛高教杯数学建模C题生产企业原材料的订购与运输解题全过程文档及程序

2021年国赛高教杯数学建模 C题 生产企业原材料的订购与运输 原题再现 某建筑和装饰板材的生产企业所用原材料主要是木质纤维和其他植物素纤维材料,总体可分为 A&#xff0c;B&#xff0c;C 三种类型。该企业每年按 48 周安排生产&#xff0c;需要提前制定 24 周的原材料订购和…

Windows Update当前无法检查更新怎么办?

当进行Windows更新或升级时&#xff0c;可能会提示“Windows Update当前无法检查更新&#xff0c;因为未运行服务。您可能需要重新启动计算机”。而当重启也无法解决问题时&#xff0c;我们该怎么办呢&#xff1f;下面我们就来了解一下。 1、删除Software Distribution文件夹中…

基于SpringBoot+SpringCloud+vue的智慧养老平台设计与实现

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

网络安全:信息收集专总结【社会工程学】

前言 俗话说“渗透的本质也就是信息收集”&#xff0c;信息收集的深度&#xff0c;直接关系到渗透测试的成败&#xff0c;打好信息收集这一基础可以让测试者选择合适和准确的渗透测试攻击方式&#xff0c;缩短渗透测试的时间。 一、思维导图 二、GoogleHacking 1、介绍 利用…

Dockerfile应用的容器化

文章目录 Dockerfile应用的容器化应用的容器化——简介应用的容器化——详解单体应用容器化获取应用代码分析Dockerfile容器化当前应用/构建具体的镜像推送镜像到仓库运行应用程序测试总结 最佳实践利用构建缓存合并镜像 命令总结 Dockerfile应用的容器化 Docker 的核心思想是…

在JDK17尝鲜Flink1.17

在JDK17尝鲜Flink1.17 前言 还没玩明白老版本&#xff0c;Flink1.17就来了&#xff01;&#xff01;&#xff01;总还是要向前看的。。。 根据官网文档&#xff1a;https://nightlies.apache.org/flink/flink-docs-release-1.17/docs/try-flink/local_installation/ Flink r…

Cyclo-(D-Tyr-Gly),1217777-38-2,环-(L-甘氨酰酪氨酸),环二肽(CDPs)作为许多活性天然产物的骨架

Cyclo-(D-Tyr-Gly)中环二肽(CDPs)作为许多活性天然产物的骨架&#xff0c;由于其独特的生物和药理活性等引起了人们的广泛关注。作为环肽化合物&#xff0c;CDPs具有短肽分子良好的生物相容性、低免疫原性等优点。Cyclo-(D-Tyr-Gly)物理参数&#xff1a; CAS号&#xff1a;1217…

Linux高性能网络编程:TCP底层的收发过程

今天探索高性能网络编程&#xff0c;但是我觉得在谈系统API之前可以先讲一些Linux底层的收发包过程&#xff0c;如下这是一个简单的socket编程代码&#xff1a; int main() {... fd socket(AF_INET, SOCKET_STREAM, 0);bind(fd, ...);listen(fd, ...);// 如何建立连接...afd …