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

news2024/11/25 8:18:39

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

一,冒泡排序

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.coloradmin.cn/o/718936.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vivado创建IP核步骤

0、创建一个LED IP核 1、打开Vivado&#xff0c;点击Tasks栏的Manage IP&#xff0c;在弹出的选项框中选中New IP Location... 2、在弹出的界面选择Next 3、在弹出的界面中进行IP核的属性配置&#xff0c;修改系所属的器件和保存路径&#xff0c;其他的保持默认就行&#xff0…

Java(117):读取properties配置文件中文乱码问题解决

1、Edit展示properties后缀文件时乱码 2、读取properties配置文件中文乱码问题解决 2.1、文件存储为UTF-8格式 2.2、读取时设置为UTF-8格式 String enconding "UTF-8"; BufferedReader br new BufferedReader(new InputStreamReader(new FileInputStream(fileP…

VMware安装win10系统(超详细)

目录 一、创建虚拟机 二、选择自定义安装 三、根据自己的主机选择虚拟机的配置 四、光盘映像可以选择稍后安装​编辑 五、 根据自己的光盘映像选择操作系统和版本&#xff0c;因为我的装的是win10 x64&#xff0c;所以安装如下图所示 六、选择存放路径 七、 选择BIOS&#x…

java阻塞队列/kafka/spring整合kafka

queue增加删除元素 增加元素 add方法在添加元素的时候&#xff0c;若超出了度列的长度会直接抛出异常&#xff1a;put方法&#xff0c;若向队尾添加元素的时候发现队列已经满了会发生阻塞一直等待空间&#xff0c;以加入元素offer方法在添加元素时&#xff0c;如果发现队列已满…

FPGA实验三:状态机的设计

目录 一、实验目的 二、实验要求 三、实验代码 1.design source文件部分代码 2.测试文件代码 四、实验结果及分析 1、引脚锁定 2、仿真波形及分析 &#xff08;1&#xff09;设计好序列检测器 &#xff08;2&#xff09;仿真波形&#xff08;检测11010&#xff09; 3…

Linux-vim与gdb与make/makefile

三个模式&#xff1a;命令模式 文本模式 底行模式 yum :instell 安装 remove 卸载 gcc -o执行后生成文件命名 gcc 1.c -o fst.out -E预编译 -S汇编 -c生成机器码 Linux 中 静态库&#xff1a;.a&#xff1b;动态库&#xff1a;.so Linux默认动态库&#xff0c;…

Redis的安装,启动,关闭

一&#xff0c;redis安装linux 1&#xff0c;安装gcc环境 yum -y install gcc-c2,上传压缩包到/usr/soft目录&#xff0c;并解压 cd /soft tar -xvf redis-3.2.11.tar.gz3&#xff0c;进入redis-5.0.7目录&#xff0c;使用make命令编译redis [rootlocalhost soft]# cd re…

【DBA课程-笔记】第1章:MongoDB数据库入门

一、MongoDB 概览及新特性 1. MongoDB 简介 目前最流行的NoSQL数据库&#xff08;NO.1&#xff09;MongoDB是一个基于分布式文件存储的数据库&#xff0c;由C语言编写&#xff0c;特点是高性能、易部署、易使用、存储数据非常方便&#xff0c;旨在为Web应用提供可扩展的高性能…

企业该如何防止数据泄漏问题

关键词&#xff1a;企业网盘、知识文档管理系统、群晖NAS、数据安全 根据Verizon《2022 数据泄露调查报告》显示&#xff0c;2022年数据泄露事件中82%的违规行为涉及人为因素&#xff0c;勒索软件泄露事件增加了13%&#xff0c;超过过去五年的总和&#xff0c;数据安全已变成关…

【JUC-7】ReentrantLock (可重入锁)基础

ReentrantLock (可重入锁) ReentrantLock实现了Lock接口, 内部通过继承AQS, 实现了一个同步器. 可以通过同步器来创建Condition条件变量, 可以用作容器, 存放不同条件的等待线程. 说明ReentrantLock与AQS的关系 类图: 相对于synchronized, 都支持可重入. 它还具备如下特点: …

【算法练习】24:凯撒密码

一、凯撒密码介绍&#xff1a; 采用替换的方式对英文字母进行处理&#xff0c;将每一个英文字符循环替换为字母表序列中该字符的后面的第三个字符&#xff0c;即循环右移3位。 明文字母表&#xff1a;ABCDEFGHIJKLMNOPQRSTUVWXYZ 密文字母表&#xff1a;DEFGHIJKLMNOPQRSTUV…

微信小程序如何读取本地云存储txt数据,避免乱码

第一步 找到你的txt文件&#xff0c;重命名为json文件 第二步 上传到云存储中&#xff0c;获取File ID 第三步 编写js代码 相关技术文档&#xff1a; https://developers.weixin.qq.com/miniprogram/dev/api/file/FileSystemManager.readFile.html onShow(){wx.cloud.d…

《Redis 核心技术与实战》课程学习笔记(三)

高性能 IO 模型&#xff1a;为什么单线程 Redis 能那么快&#xff1f; Redis 是单线程&#xff0c;主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的&#xff0c;这也是 Redis 对外提供键值存储服务的主要流程。但 Redis 的其他功能&#xff0c;比如持久化、异步删…

CDS Core Data Services S4 CDS view--2

7.2 怎么加注释 首先要看懂注释&#xff0c;comparefilter 一般都是true,这样在association 里的join只被验证一次&#xff0c;如果是FALSE就会不停的被验证。 preservekey, 验证和数据库表的key是否一致。 authorizationcheck, 需要验证权限。不过我们没有设access control…

STM32F1 GPIO 简介

GPIO 是控制或者采集外部器件的信息的外设&#xff0c;即负责输入输出。它按组分配&#xff0c;每组 16 个 IO 口&#xff0c;组数视芯片而定。STM32F103ZET6 芯片是 144 脚的芯片&#xff0c;具有 GPIOA、GPIOB、GPIOC、 GPIOD、GPIOE、GPIOF 和 GPIOG 七组 GPIO 口&#xff0…

13---罗马数字转整数

罗马数字包含以下七种字符: I&#xff0c; V&#xff0c; X&#xff0c; L&#xff0c;C&#xff0c;D 和 M。 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如&#xf…

【DBA课程-笔记】MongoDB入门到云上开发

课程目的&#xff1a;成为专业MongoDB的DBA nosql第一&#xff1a;MongoDB 一、讲师&#xff1a; 二、课程目录 第1章&#xff1a;MongoDB数据库入门 第2章&#xff1a;MongoDB数据数据查询与分析 第3章&#xff1a;MongoDB数据库核心知识 第4章&#xff1a;MongoDB数据库管…

时间序列预测 | Matlab基于粒子群算法优化门控循环单元(PSO-GRU)的时间序列预测,PSO-GRU时间序列预测,单列数据集

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 时间序列预测 | Matlab基于粒子群算法优化门控循环单元(PSO-GRU)的时间序列预测,PSO-GRU时间序列预测,单列数据集。 优化参数为学习率,隐藏层节点个数,正则化参数,要求2020b及以上版本&#

Redhat7.6安装mysql5.7

环境准备&#xff1a;硬盘剩余空间最少8G,内存剩余最少2G Mysql官网下载地址&#xff1a;https://dev.mysql.com/downloads/mysql/5.7.html 在Mysql官网下载列表中选择需要安装的版本: RedHat7.6安装MySQL5.7 安装之前&#xff0c;先要保证系统环境是干净的&#xff0c;不能存…

Dual In-Line Package(双列直插式封装)和Pin Grid Array Package(针栅阵列插入式封装)

DIP封装示意图 1.Dual In-Line Package&#xff08;双列直插式封装&#xff09; DIP的详细介绍&#xff1a; 1.封装形式&#xff1a;DIP是一种插件式封装&#xff0c;它由一个狭长的塑料或陶瓷封装体组成&#xff0c;具有在两侧排列的引脚。引脚通常是分布均匀的&#xff0c…