常见排序算法性能分析比较(快排,希尔,堆排,归并,插入排序等)

2023-05-16

文章目录

  • 1.各种排序算法实现及其特点
    • 1.1 直接插入排序
    • 1.2 希尔排序
    • 1.3 直接选择排序
    • 1.4 堆排序
    • 1.5 冒泡排序
    • 1.6 快速排序
    • 1.7 归并排序
    • 1.8 计数排序
  • 2.排序算法复杂度及稳定性分析

1.各种排序算法实现及其特点

在这里插入图片描述

1.1 直接插入排序

直接插入排序的特性总结:

  1. 元素集合越接近有序,直接插入排序算法的时间效率越高
  2. 时间复杂度:O(N^2)
  3. 空间复杂度:O(1),它是一种稳定的排序算法
  4. 稳定性:稳定

void Swap(int* a, int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}
//直接插入排序-从前往后比较
void InsertSort_1(int* ar, int left, int right)
{
	for (int i = left + 1; i < right; ++i)
	{
		int k = left;
		while (ar[i] > ar[k])
			k++;

		int tmp = ar[i];
		for (int j = i; j > k; --j)
			ar[j] = ar[j - 1];

		ar[k] = tmp;
	}
}
//直接插入排序-从后往前比较
void InsertSort_2(int* ar, int left, int right)
{
	for (int i = left + 1; i < right; ++i)
	{
		int j = i;
		while (j > left && ar[j] < ar[j - 1])
		{
			Swap(&ar[j], &ar[j - 1]);
			j--;
		}
	}
}

//直接插入排序-从后往前比较不调用交换函数
void InsertSort_3(int* ar, int left, int right)
{
	for (int i = left + 1; i < right; ++i)
	{
		int j = i;
		int tmp = ar[j];
		while (j > left && tmp < ar[j - 1])
		{
			ar[j] = ar[j - 1];
			j--;
		}

		ar[j] = tmp;
	}
}

//直接插入排序-哨兵位
void InsertSort_4(int* ar, int left, int right)
{
	for (int i = left + 1; i < right; ++i)
	{
		ar[0] = ar[i];  //哨兵位
		int j = i;
		while (ar[0] < ar[j - 1])
		{
			ar[j] = ar[j - 1];
			j--;
		}
		ar[j] = ar[0];
	}
}
//折半插入排序
void BinInsertSort(int* ar, int left, int right)
{
	for (int i = left + 1; i < right; ++i)
	{
		int tmp = ar[i];
		int low = left;
		int high = i - 1;
		int mid;
		while (low <= high)  //折半查找插入位置
		{
			mid = (low + high) / 2;
			if (tmp >= ar[mid])
				low = mid + 1;
			if (tmp < ar[mid])
				high = mid - 1;
		}

		for (int j = i; j > low; --j)
			ar[j] = ar[j - 1];

		ar[low] = tmp;
	}
}


//二路插入排序   空间复杂度 O(n)
void TwoWayInsertSort(int* ar, int left, int right)
{
	int n = right - left;
	int* tmp = (int*)malloc(sizeof(int) * n);

	tmp[0] = ar[left];
	int first, final;
	first = final = 0;
	for (int i = left + 1; i < right; ++i)
	{
		if (ar[i] < tmp[first])
		{
			first = (first - 1 + n) % n;
			tmp[first] = ar[i];
		}
		else if (ar[i] >= tmp[final])
		{
			tmp[++final] = ar[i];
		}
		else
		{
			int end = final;
			while (ar[i] < tmp[end])
			{
				tmp[(end + 1) % n] = tmp[end];
				end = (end - 1 + n) % n;
			}
			tmp[(end + 1) % n] = ar[i];
			final++;
		}
	}

	int k = 0;
	for (int i = first; k < n; ++k)
	{
		ar[k] = tmp[i];
		i = (i + 1) % n;
	}
	free(tmp);
}

1.2 希尔排序

希尔排序的特性总结:

  1. 希尔排序是对直接插入排序的优化。
  2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就
    会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
  3. 希尔排序的时间复杂度不好计算,需要进行推导,推导出来平均时间复杂度: O(N1.3—N2)
  4. 稳定性:不稳定。


void ShellSort(int* ar, int left, int right)
{
	int gap = right - left;
	while (gap > 1)
	{
		gap = gap / 3 + 1; //4  2  1  设计文档
		for (int i = left + gap; i < right; ++i)
		{
			if (ar[i] < ar[i - gap])
			{
				int tmp = ar[i];
				int j = i;
				while (j > left && tmp < ar[j - gap])
				{
					ar[j] = ar[j - gap];
					j = j - gap;
				}

				ar[j] = tmp;
			}
		}
	}
}

1.3 直接选择排序

直接选择排序的特性总结:

  • 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用
  • 时间复杂度:O(N^2)
  • 空间复杂度:O(1)
  • 稳定性:不稳定

void Swap(int* a, int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}
//简单选择排序

int GetMinIndex(int* ar, int left, int right)
{
	int min_value = ar[left];
	int index = left;

	for (int i = left + 1; i < right; ++i)
	{
		if (ar[i] < min_value)
		{
			min_value = ar[i];
			index = i;
		}
	}
	return index;
}

void SelectSort(int* ar, int left, int right)
{
	for (int i = left; i < right - 1; ++i)
	{
		int index = GetMinIndex(ar, i, right);
		if (index != i)
			Swap(&ar[i], &ar[index]);
	}
}

1.4 堆排序

堆排序:需要注意的是排升序要建大堆,排降序建小堆。

  • 堆排序使用堆来选数,效率就高了很多。
  • 时间复杂度:O(N*logN)
  • 空间复杂度:O(1)
  • 稳定性:不稳定
//堆排  这里是升序排列 建立大堆  需要向下调整
void _AdjustDown(int* ar, int left, int right, int start)
{
	int n = right - left;
	int i = start;    //代表父节点
	int j = 2 * i + 1;  //代表i节点的左子树

	int tmp = ar[i];

	while (j < n)
	{
		if (j + 1 < n && ar[j] < ar[j + 1])
			j = j + 1;

		if (tmp < ar[j])
		{
			ar[i] = ar[j];
			i = j;
			j = 2 * i + 1;
		}
		else
			break;
	}

	ar[i] = tmp;
}
void HeapSort(int* ar, int left, int right)
{
	int n = right - left;
	int curpos = n / 2 - 1 + left; //找到二叉树的最后一个分支
	while (curpos >= 0)
	{
		_AdjustDown(ar, left, right, curpos);
		curpos--;
	}

	//排序
	int end = right - 1;
	while (end > left)
	{
		Swap(&ar[left], &ar[end]); //出堆
		_AdjustDown(ar, left, end, 0);
		end--;
	}
}

1.5 冒泡排序

冒泡排序的特性总结:

  • 冒泡排序是一种非常容易理解的排序
  • 时间复杂度:O(N^2)
  • 空间复杂度:O(1)
  • 稳定性:稳定
//冒泡排序
void BubbleSort_1(int* ar, int left, int right)
{
	for (int i = left; i < right - 1; ++i)
	{
		for (int j = left; j < right - i - 1; ++j)
		{
			if (ar[j] > ar[j + 1])
			{
				Swap(&ar[j], &ar[j + 1]);
			}
		}
	}
}
//改进  无交换时可以退出循环
void BubbleSort_2(int* ar, int left, int right)
{
	bool is_swap = false;
	for (int i = left; i < right - 1; ++i)
	{
		for (int j = left; j < right - i - 1; ++j)
		{
			if (ar[j] > ar[j + 1])
			{
				Swap(&ar[j], &ar[j + 1]);
				is_swap = true;
			}
		}
		if (!is_swap)
			break;
		else
			is_swap = false;
	}
}

1.6 快速排序

快速排序:
实现方法常有三种:

1. hoare版本
2. 挖坑法
3. 前后指针版本

代码实现均有。
特点:
1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
2. 时间复杂度:O(N*logN)
3. 空间复杂度:O(logN)
4. 稳定性:不稳定

//快速排序
int GetMidIndex(int* ar, int left, int right)
{
	int mid = (left + right - 1) / 2;
	if (ar[left] < ar[mid] && ar[mid] < ar[right - 1])
		return mid;
	if (ar[left] > ar[mid] && ar[left] < ar[right - 1])
		return left;
	return right - 1;
}

//hoare 法
int _Partition_1(int* ar, int left, int right)
{
	int low = left, high = right - 1;
	int key = ar[low];
	while (low < high)
	{
		while (low<high && ar[high]>key)
			high--;
		Swap(&ar[low], &ar[high]);

		while (low < high && ar[low] <= key)
			low++;
		Swap(&ar[low], &ar[high]);
	}
	return low;
}
//挖坑法
int _Partition_2(int* ar, int left, int right)
{
	int low = left, high = right - 1;
	int key = ar[low];
	while (low < high)
	{
		while (low<high && ar[high]>key)
			high--;
		ar[low] = ar[high];
		while (low < high && ar[low] <= key)
			low++;
		ar[high] = ar[low];
	}
	ar[low] = key;
	return low;  //曲轴点
}
//前后指针法
int _Partition_3(int* ar, int left, int right)
{
	int mid_index = GetMidIndex(ar, left, right);   //前中后三者取中间值作为用来比较的值
	if (mid_index != left)
		Swap(&ar[mid_index], &ar[left]);
	///

	int key = ar[left];
	int pos = left;
	for (int i = pos + 1; i < right; ++i)
	{
		if (ar[i] < key)
		{
			pos++;
			if (pos != i)
			{
				Swap(&ar[pos], &ar[i]);
			}
		}
	}
	Swap(&ar[left], &ar[pos]);
	return pos;
}

#define M 5     

void QuickSort(int* ar, int left, int right)
{
	if (left >= right)
		return;

	if (right - left <= M) //改进   这里元素个数少的时候 选择插入排序
		InsertSort_3(ar, left, right);
	else
	{
		int pos = _Partition_3(ar, left, right);
		QuickSort(ar, left, pos);    // 左子序列
		QuickSort(ar, pos + 1, right); // 右子序列
	}
}

1.7 归并排序

归并排序的特性总结:

  • 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
  • 时间复杂度:O(N*logN)
  • 空间复杂度:O(N)
  • 稳定性:稳定
//归并排序
void _MergeSort(int* ar, int left, int right, int* tmp)
{
	if (left >= right)
		return;
	int mid = (left + right) / 2;
	_MergeSort(ar, left, mid, tmp); // 分解左边分支
	_MergeSort(ar, mid + 1, right, tmp); //分解右边分支

	//开始归并
	int begin1, end1, begin2, end2;
	begin1 = left, end1 = mid;
	begin2 = mid + 1, end2 = right;

	int k = left; //
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (ar[begin1] < ar[begin2])
			tmp[k++] = ar[begin1++];
		else
			tmp[k++] = ar[begin2++];
	}

	while (begin1 <= end1)
		tmp[k++] = ar[begin1++];
	while (begin2 <= end2)
		tmp[k++] = ar[begin2++];

	memcpy(ar + left, tmp + left, sizeof(int) * (right - left + 1));
}

void MergeSort(int* ar, int left, int right)
{
	int n = right - left;
	int* tmp = (int*)malloc(sizeof(int) * n);

	_MergeSort(ar, left, right - 1, tmp);

	free(tmp);
}

1.8 计数排序

计数排序的特性总结:
j计数排序思想

计数排序为非比较排序:

  • 计数排序在数据范围集中时,效率很高,但是适用范围及场景有限.
  • 时间复杂度:O(MAX(N,范围))
  • 空间复杂度:O(范围)
  • 稳定性:稳定

2.排序算法复杂度及稳定性分析

排序算法复杂度及稳定性分析

排序算法复杂度及稳定性分析

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

常见排序算法性能分析比较(快排,希尔,堆排,归并,插入排序等) 的相关文章

  • 【PADS】PADS覆铜技巧

    目录 重要快捷键 基础设置 层设置 电源层分割处理 给自己喜欢的网络上个颜色 TOP层覆铜 验证设计是否有问题 PADS开窗 PADS为分割层模拟数字地覆网格铜 PADS 快捷键 Ctrl 43 鼠标滚轮失灵 Ctrl 43 鼠标滚轮造成P
  • 【Cadence16.6】安装教程

    初识安装包文件 我们cadence16 6的安装包是这样的 xff0c 详细请去https www fanyedu com index mulitcourse video html id 61 1008 1008观看 首先我们打开这个文件夹
  • 【硬件】芯片温度/功耗计算

    本博客参考 xff1a 一纸沙漏的博客 芯片的四个温度 内核温度 封装表面温度 空气周边温度以及PCB板温度 TJ xff08 Die Junction Temp xff09 芯片的硅核温度 xff0c 就是芯片内部核心的温度 xff0c
  • Python unicode 字符串 转 list

    unicode 字符串 转 list unicodeList 61 u 39 100 100 100 100 100 100 39 1 方法一 list 61 eval unicodeList 2 方法二 int value for val
  • 【硬件】AD623单电源供电差分放大

    1 前言 检测电机电流运用检流电阻的方法在往期已经介绍过 详情请见 xff1a 检流电阻计算电流 2 需求分析 2 1 电机流过电流 已知电机的峰值堵转电流为4 6A xff0c 连续堵转电流为3 2A xff0c 以上信息可以得知需要采样
  • 【电路】PT1000/PT100温度采集电路

    目录 原理图下载链接 xff1a https download csdn net download Roger 717 33823983https download csdn net download Roger 717 33823983h
  • 【QT】手把手制作一个QT网络调试助手(准备阶段)

    目录 1 新建一个工程 2 mainwindow ui设计 2 1 对窗口主体进行栅格化布局 2 2 添加网络通信配置GroupBox 2 2 1 填充内容 2 2 2 栅格布局GroupBox 2 3 总结 3 Pro程序配置 4 头文件
  • 【PR】PR视频剪辑实用技巧

    1 两个视频叠加 1 首先 xff0c 找到要导入的视频所在文件夹 xff0c 将视频拖动到项目面板中 按住Ctrl拖动视频再复制两个视频 2 将素材视频分别拖入到序列的 视频轨道1 2 3 3 点击选中轨道1上的视频 xff0c 在源面板
  • 【Project】项目管理软件学习笔记

    一 前言 使用Project制定项目计划步骤大致如下 xff1a 以Project2013为例 xff0c 按照上图步骤指定项目计划 二 实施 2 1 创建空白项目 点击文件 新建 空白项目 xff0c 即完成了空白项目的创建 xff0c
  • 【硬件】P沟道和N沟道MOS管开关电路设计

    场效应管做的开关电路一般分为两种 xff0c 一种是N沟道 xff0c 另一种是P沟道 xff0c 如果电路设计中要应用到高端驱动 的话 xff0c 可以采用PMOS来导通 P沟道MOS管开关电路 PMOS的特性 xff0c Vgs小于一定
  • 多线程基础之七:多线程遇上printf的“延迟写”策略

    0 运行库提供的IO读写函数采用 延迟写 策略的原因 编程时经常会用到printf 函数 xff0c 但是由于printf 函数涉及到和显示器或磁盘等外设进行交互 xff0c 所以操作涉及到从 用户态 gt 内核态 gt 返回用户态 的一系
  • VC和VS区别

    S是Visual Studio xff0c 它是微软提供的一个工具集 xff0c 由各种各样的工具组成 VS可以支持C C 43 43 VB JAVA C 编程 然了一次只能支持一种编程方式 在VS安装完成 xff0c 第一次运行的时候会让
  • 【potplayer安装及设置LAV Splitter】

    potplayer安装及设置LAV Splitter 下载及安装Lav Splitter解码器配置Lav Splitter解码器 potplayer是一款windows平台上一款轻量功能强大的播放器 xff0c 它界面简洁 xff0c 功能
  • 关于头文件的相互包含

    编程过程中 xff0c 经常会碰到头文件的相互包含 xff0c 如果处理不慎 xff0c 就会报错 比如在头文件A h中有如下代码 xff08 代码中的B Handle是在头文件B h中定义的 xff09 xff1a span class
  • Python list中去重的多种方法

    去重之后顺序会改变 set去重 列表去重会让列表改变原来的顺序 l1 61 1 4 4 2 3 4 5 6 1 l2 61 list set l1 print l2 1 2 3 4 5 6 但是 xff0c 可以通过列表中索引 xff08
  • TI学习笔记之“振动补偿算法”

    一些应用中 xff0c 负载和机械角度有关 xff0c 比如空调压缩机 典型压缩机应用的负载曲线如下图所示 xff0c 不难发现 xff0c 在一个机械周期内 xff0c 负载和机械角度存在一定的关系 xff0c 这种情况在转子式压缩机中尤
  • “compilerPath“的问题

    在c cpp properties josn文件中 xff0c complierPath的问题解决如下 如果正在编译c 43 43 文件 xff0c 先在终端输入which g 43 43 我的弹出了 usr bin g 43 43 把这个
  • Digest Authentication Response 如何计算

    Session Initiation Protocol NOTIFY Request Line NOTIFY sip 192 168 125 130 5060 SIP 2 0 Method NOTIFY Request URI sip 19
  • ROS-Melodic 编译Moveit全过程记录和错误解决方案

    ROS Melodic 编译Moveit全过程记录和错误解决方案 在Ros Melodic版本下 xff0c 直接运行sudo apt get install ros melodic moveit会出现以下错误 xff1a 下列软件包有未满
  • Jetson TX2在ROS下使用Realsense D435i跑rtabmap、octomap、VINS-Mono和ORB-SLAM2

    使用环境 xff1a Ubuntu 16 04 JetPack 3 3 xff0c ROS Kinetic硬件设备 xff1a 英伟达Jetson TX2 xff0c 英特尔Realsense D435i 安装Realsense相关的相机驱

随机推荐

  • C++实现流式socket聊天程序

    目录 协议设计 消息的类型 消息的语法 消息的语义 消息的处理 发送消息 接收消息 程序设计 模块的划分和功能 Client客户端 Server服务器 模块流程图 程序实现 辅助代码 client cpp server cpp 程序测试 本
  • STM32 串口 FIFO

    使用FIFO实现串口数据的收发功能 FIFO的相关实现参照链接 xff1a CSDN https mp csdn net mp blog creation editor 120448361 1 Cubemx串口配置 使用Cubmx对串口进行
  • C Primer Plus

    C Primer Plus作为一本被人推崇备至的c入门经典 xff0c C primer plus绝非浪得虚名 应该算得上C教材里最好的入门书了 在知识广度上 xff0c 很少有书能匹及 它能为你系统学习c提供一个良好的平台 作者对c的见解
  • Python 如何处理大文件

    Python作为一门程序设计语言 xff0c 在易读 易维护方面有独特优势 xff0c 越来越多的人使用 Python 进行数据分析和处理 xff0c 而 Pandas 正是为了解决数据分析任务而创建的 xff0c 其包含大量能便捷处理数据
  • C++构造DHCP Discovery报文并使用socket发送

    DHCP由BOOTP协议发展而来 xff0c 而后者基于UDP IP协议 xff0c 这使得使用socket发送DHCP报文成为可能 本文示例构造了DHCP Discovery报文并调用socket接口发送 xff0c 值得注意的是 xff
  • pycharm 常用快捷键整理

    pycharm常用快捷键 1 编辑 xff08 Editing xff09 Ctrl 43 Space 基本的代码完成 xff08 类 方法 属性 xff09 Ctrl 43 Alt 43 Space 快速导入任意类 Ctrl 43 Shi
  • RTT串口V1版本的使用分析及问题排查指南(一)

    本文由RT Thread论坛用户123原创发布 xff1a https club rt thread org ask article 2894 html RTT串口V1版本的使用分析及问题排查指南 一 简述 无论是刚接触 RT Thread
  • 总结基于寄存器与基于固件库stm32编程的差异

    基于寄存器与基于固件库stm32编程方式有什么差异 总的来说是专业层面或者说是应用层面的区别 总的来说是专业层面或者说是应用层面的区别 从应用角度讲 xff0c 寄存器相对来说是属于更底层的 xff0c 类似于驱动层 xff0c 而固件库则
  • Python 3中HTTPparse 的使用

    在python中能够进行html和xhtml的库有很多 xff0c 如HTMLParser sgmllib htmllib BeautifulSoup mxTidy uTidylib等 xff0c 这里介绍一下HTMLParser Beau
  • STorM32三轴云台控制器PID参数调节(1)

    本文是一篇利用STorM32板子控制三轴云台的经验贴 xff0c 内容包括从所有的硬件到位开始到pid参数调节完成中的一些经验 xff0c 完成这一步后 xff0c 就可以拥有一个稳定的云台了 本文是基于 STorM32 BGC32Bit
  • Centos libevent install

    1 下载安装包 xff1a 官网 http libevent org libevent 2 1 8 stable tar gz 2 解压 tar zxvf libevent 2 1 8 stable tar gz 3 进入目录 cd lib
  • windows waveIn 录音

    windows waveIn 录音 编写背景1查找设备2 根据设备名称找到设备3 打开设备4 开始录音5 结束录音 编写背景 windows xp 系统不支持 WASAPI xff0c 选择 waveIn API 1查找设备 获取音频设备数
  • waveIn 录音遇到的问题与解决方案

    问题点 1 录音过程中拔出设备 xff0c 程序死锁 添加缓存的之前需要检查设备是否存在 case WIM DATA if xff08 is device exsit xff09 设备是否存在 xff0c 可以通过获取设备信息来判断 预处理
  • vs2013编译32位的libcurl

    编译 libcurl 下载 CURL源码打开 VS2013 x86 本机工具命令提示cd 进入 curl 源码 winbuild 目录执行命令 xff1a nmake f Makefile vc mode 61 static VC 61 1
  • python两个列表获取交集,并集,差集

    list1 61 1 2 3 4 5 6 list2 61 2 3 4 交集 方法一 xff1a list3 61 new for new in list1 if new in list2 方法二 xff1a list3 61 list s
  • FFMPEG 指令

    ffplay 拉取流 ffplay exe i rtmp address fflags nobuffer ffmpeg commend lines 只推屏幕 dshow 模式 ffmpeg ffmpeg exe f dshow i vide
  • 电子罗盘

    电子罗 种重要的导航工具 xff0c 能实时提供移动物体的航向和姿态 随着半导体工艺的进步和手机操作系统的发展 xff0c 集成了越来越多传感器的智能手机变得功能强大 xff0c 很多手机上都实现了电子罗盘的功能 而基于电子罗盘的应用 xf
  • C++中的.和::和:和->的区别

    在学习C 43 43 的过程中我们经常会用到 和 和 xff1a 和 gt xff0c 在此整理一下这些常用符号的区别 1 A B则A为对象或者结构体 xff1b 2 A gt B则A为指针 xff0c gt 是成员提取 xff0c A g
  • STM32 HAL库函数学习 UART篇

    从今天开始定时更新一下有关STM32 HAL库学习的过程 xff0c 主要是对HAL库函数的所有讲解 本章是关于uart串口的函数 1 HAL UART Init xff08 UART HandleTypeDef husart xff09
  • 常见排序算法性能分析比较(快排,希尔,堆排,归并,插入排序等)

    文章目录 1 各种排序算法实现及其特点1 1 直接插入排序1 2 希尔排序1 3 直接选择排序1 4 堆排序1 5 冒泡排序1 6 快速排序1 7 归并排序1 8 计数排序 2 排序算法复杂度及稳定性分析 1 各种排序算法实现及其特点 1