IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 排序算法(二)——交换排序【C/C++】 -> 正文阅读

[C++知识库]排序算法(二)——交换排序【C/C++】


前言

这里保存个人对常见交换排序算法的理解和实现思路过程。
供大家学习和参考。


一、几点注意

对于耗时时间,随机数选取,单调性的问题详见排序算法(一)。

二、交换类排序

2.1 交换类排序的分类

常见的交换类排序分为冒泡排序,快速排序等等,这里着重实现这两种插入排序。

2.2 冒泡排序

2.2.1 冒泡排序的思路

反复扫描待排序的记录序列,在扫描的过程中顺次比较相邻的两个元素的大小,若逆序就交换位置。每趟冒泡排序都将一个记录排到位,知道剩下一个最小的记录。若在某一趟中未发现一个逆序,则结束整个排序过程。

2.2.2 具体代码

void Swap(int* a, int* b) {
	int temp = *b;
	*b = *a;
	*a = temp;
}
void BubbleSort(int* arr, int n) {
	int i, j;
	for (i = 0; i <= n - 1; i++) {
		for (j = 1; j <= n - 1; j++) {
			if (arr[j - 1] > arr[j]) {
				Swap(&arr[j - 1], &arr[j]);
			}
		}
	}
}

2.2.3 测试代码

冒泡排序
在这里插入图片描述
对于10000个数据的处理结果(随机数选取10000以内的)
在这里插入图片描述

多次尝试后,冒泡排序的时间对于10000个数据处理在390ms到400ms之间

2.2.4 稳定性分析

冒泡排序因为是相邻的两两交换因此冒泡排序是稳定的。

2.3 快速排序

2.3.1 快速排序的思路

思想:从待排序记录序列中选取一个记录(通常选取第一个记录)为枢轴,其关键字设为k1,然后将其余关键小于k1的记录移到前面,而将关键字大于或等于k1的记录移到后面,将待排序记录序列分成两个子表,最后将关键字为的k1的记录插到其分界线的位置处。将这个过程称为一趟快速排序。之后再对分割后的子表继续按上述原则分割,直到所有子表表长不超过1为止,此时待排序记录就变成了有序表。

2.3.2 具体代码

void QuickSort(int* arr, int low, int high) {
	int first = low;//记录下边界
	int end = high;//记录上边界
	if (low < high) {
		int index = arr[low];
		while (low < high) {
			while (low < high && arr[high] >= index) {
				high--;
			}
			arr[low] = arr[high];
			while (low < high && arr[low] <= index) {
				low++;
			}
			arr[high] = arr[low];
		}
		arr[low] = index;
		QuickSort(arr, first, low - 1);
		QuickSort(arr, low + 1, end);
	}
}

2.3.3 测试结果

在这里插入图片描述
对于10000个数据的处理结果(随机数选取10000以内的)
在这里插入图片描述
对于10000个数据的处理快速排序只用了1ms,比起前两个快的多。

2.3.4 稳定性

快速排序因为是左右同时交换,所以存在将相同元素换到相反的方向的可能,所以是不稳定的。

2.4 两种交换排序的对比

冒泡排序

时间复杂度:平均情况下为O(N2)。
??????最好情况下为O(N),顺序。
??????最坏情况下为O(N2)。
空间复杂度:因为每回只移动一个所以空间复杂度为O(1)。
稳定性:稳定。

快速排序

时间复杂度:平均情况下为O(Nlog2N)。
??????最好情况下为O(Nlog2N),每趟排序分为两半,类似于折半查找。
??????最坏情况下O(N2),已经排好序。
空间复杂度:O(Nlog2N)。
从空间性能上看,尽管快速排序只需要一个元素的辅助空间,但快速排序需要一个栈空间来实现递归。最好的情况下,即快速排序的每一趟排序都将元素序列均匀地分割成长度相近的两个子表,所需栈的最大深度为log2(n+1);但最坏的情况下,栈的最大深度为n。这样,快速排序的空间复杂度为O(log2n)
稳定性:不稳定。

三、对于已有排序算法的使用

3.1 qsort()的使用

对于C语言的头文件#include< algorithm >中提供一种快速排序的函数使用。

3.1.1 qsort()函数简介

void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))

参数
base– 指向要排序的数组的第一个元素的指针。
nitems– 由 base 指向的数组中元素的个数。
size– 数组中每个元素的大小,以字节为单位。
compar– 用来比较两个元素的函数,即函数指针(回调函数)

参数中compar需要我们自己写回调函数,这里就要复习一下函数指针的问题了。

3.1.2 函数指针的使用

函数指针的声明方法为:

返回值类型 ( * 指针变量名) ([形参列表]);

我们要记住无论是[],还是(),运算优先级都要比*高。这样我们就能理解什么是函数指针了。
定义函数指针有三种方式
先设置一个fun函数

int fun (int a){
	printf("a = %d\n",a);
	return 0;
}

第一种:先定义函数类型,根据类型定义指针变量。

typedef int FUN (int); //FUN函数类型
FUN *p1=NULL; //函数指针变量
p1=fun; //p1指向fun函数
fun(5); //传统调用
p1(5); //函数指针变量

第二种:先定义函数指针类型,根治类型定义指针变量

typedef int(*PFUN)(int); //PFUN函数指针类型
PFUN p2=fun; //p2指向fun
p2(5); 

第二种这种定义不太明显不建议使用。
第三种:直接定义函数指针类型(常用)

int(*p3)(int)fun;
p3(5);

或者

int (*p4)(int a);
p4=fun;
p4(5);

3.1.3 qsort()的具体使用

有了刚刚函数指针的学习,对于回调函数compar我们也就有个了解
因此先对int (*compar)(const void , const void)写回调函数

int compare(const void* left, const void* right) {
	return *(int*)left - *(int*)right;
}

接着调用qsort()。

qsort(arr, n, sizeof(int), compare);

3.1.4 qsort()测试

在这里插入图片描述

3.2 sort()的使用

对于C++中,头文件algorithm中存在sort()函数
记得加using namespace std;

3.2.1 sort()函数简介

template< class RandomIt >
void sort( RandomIt first, RandomIt last );    
template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp );

参数
(1)first表示要排序数组的起始地址;
(2)last表示数组结束地址的下一位;
(3)comp用于规定排序的方法,可不填,默认升序。
sort()可以对链表、结构体等等进行排序,不过要自己写回调函数,这里就只测试对于数组的排序。

3.2.2 sort()具体调用

对于数组arr的调用

sort(a, a + n);

3.2.3 测试结果

在这里插入图片描述

四、对于几个性能比较高的算法的比较

对于100000个数据,随机数选取在100000以内。
这里只比较了我自己写的快排和希尔,以及库函数里的qsort和sort。
在这里插入图片描述

对于1000000个数据,随机数选取在1000000以内
在这里插入图片描述
说实话我也不知道为啥自己写的快排效率要比库函数的qsort()要好。


总结

对于交换类排序的总结就到这里,有问题欢迎大家指正。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-09-21 00:08:17  更:2022-09-21 00:09:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:21:27-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码