排序的概念以及几种基本常用排序

这篇具有很好参考价值的文章主要介绍了排序的概念以及几种基本常用排序。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.排序的概念及其运用

1.1排序的概念

排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次
序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
内部排序:数据元素全部放在内存中的排序。
外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序

1.2 常见的排序算法

排序的概念以及几种基本常用排序,排序算法,算法

2.常见排序算法的实现

2.1 插入排序

2.1.1基本思想

直接插入排序是一种简单的插入排序法,其基本思想是:把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为
止,得到一个新的有序序列 。
实际中我们玩扑克牌时,就用了插入排序的思想
排序的概念以及几种基本常用排序,排序算法,算法

2.1.2直接插入排序

// 时间复杂度:O(N^2) 逆序
// 最好的情况:O(N)  顺序有序
void InsertSort(int* a, int n)
{
	// [0, end] end+1
	for (int i = 0; i < n-1; ++i)
	{
		int end = i;
		int tmp = a[end + 1];
		while (end >= 0)
		{
			if (tmp > a[end])
			{
				a[end + 1] = a[end];
				--end;
			}
			else
			{
				break;
			}
		}

		a[end + 1] = tmp;
	}
}

当插入第i(i>=1)个元素时,前面的array[0],array[1],…,array[i-1]已经排好序,此时用array[i]的排序码与
array[i-1],array[i-2],…的排序码顺序进行比较,找到插入位置即将array[i]插入,原来位置上的元素顺序后移
直接插入排序的特性总结:

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

2.1.3 希尔排序( 缩小增量排序 )

// O(N^1.3)
void ShellSort(int* a, int n)
{
	int gap = n;

	// gap > 1时是预排序,目的让他接近有序
	// gap == 1是直接插入排序,目的是让他有序
	while (gap > 1)
	{
		//gap = gap / 2;
		gap = gap / 3 + 1;

		for (int i = 0; i < n - gap; ++i)
		{
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (tmp < a[end])
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}


希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序
排序的概念以及几种基本常用排序,排序算法,算法
希尔排序的特性总结:

  1. 希尔排序是对直接插入排序的优化。
  2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
  3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些树中给出的希尔排序的时间复杂度都不固定
  4. 稳定性:不稳定

2.2 选择排序

2.2.1基本思想

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完

2.2.2 直接选择排序

// 时间复杂度:O(N^2)
// 最好的情况下:O(N^2)
void SelectSort(int* a, int n)
{
	int begin = 0, end = n - 1;

	while (begin < end)
	{
		int mini = begin, maxi = begin;
		for (int i = begin + 1; i <= end; ++i)
		{
			if (a[i] < a[mini])
			{
				mini = i;
			}

			if (a[i] > a[maxi])
			{
				maxi = i;
			}
		}

		Swap(&a[begin], &a[mini]);
		if (maxi == begin)
		{
			maxi = mini;
		}
		Swap(&a[end], &a[maxi]);

		++begin;
		--end;
	}
}

在元素集合array[i]–array[n-1]中选择关键码最大(小)的数据元素
若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换在剩余的array[i]–array[n-2](array[i+1]–array[n-1])集合中,重复上述步骤,直到集合剩余1个元素
直接选择排序的特性总结:

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

2.2.3 堆排序

void AdjustDown(int* a, int size, int parent)
{
	int child = parent * 2 + 1;

	while (child < size)
	{
		// 假设左孩子小,如果解设错了,更新一下
		if (child + 1 < size && a[child + 1] > a[child])
		{
			++child;
		}

		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

// 升序
void HeapSort(int* a, int n)
{
	// O(N)
	// 建大堆
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(a, n, i);
	}

	// O(N*logN)
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		--end;
	}
}

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆
排序的概念以及几种基本常用排序,排序算法,算法
直接选择排序的特性总结:

  1. 堆排序使用堆来选数,效率就高了很多。
  2. 时间复杂度:O(N*logN)
  3. 空间复杂度:O(1)
  4. 稳定性:不稳定

2.3 交换排序

基本思想:所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,交换排
序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。

2.3.1冒泡排序

// 时间复杂度:O(N^2)
// 最好情况是多少:O(N)
void BubbleSort(int* a, int n)
{
	for (int j = 0; j < n; j++)
	{
		bool exchange = false;
		for (int i = 1; i < n-j; i++)
		{
			if (a[i - 1] > a[i])
			{
				Swap(&a[i - 1], &a[i]);
				exchange = true;
			}
		}

		if (exchange == false)
			break;
	}
	

	//for (int i = 0; i < n-1; i++)
	//{
	//	if (a[i] > a[i+1])
	//	{
	//		Swap(&a[i], &a[i+1]);
	//	}
	//}
}

冒泡排序的特性总结:

  1. 冒泡排序是一种非常容易理解的排序
  2. 时间复杂度:O(N^2)
  3. 空间复杂度:O(1)
  4. 稳定性:稳定

2.3.2 快速排序

2.3.2.1 hoare版本
int PartSort1(int* a, int begin, int end)
{
	int midi = GetMidi(a, begin, end);
	Swap(&a[midi], &a[begin]);

	int left = begin, right = end;
	int keyi = begin;

	while (left < right)
	{
		// 右边找小
		while (left < right && a[right] >= a[keyi])
		{
			--right;
		}

		// 左边找大
		while (left < right && a[left] <= a[keyi])
		{
			++left;
		}

		Swap(&a[left], &a[right]);
	}

	Swap(&a[left], &a[keyi]);

	return left;
}
void QuickSort(int* a, int begin, int end)
{
	if (begin >= end)
		return;

	int keyi = PartSort3(a, begin, end);
	QuickSort(a, begin, keyi - 1);
	QuickSort(a, keyi+1, end);
}
2.3.2.2 挖坑法
// 挖坑法
int PartSort2(int* a, int begin, int end)
{
	int midi = GetMidi(a, begin, end);
	Swap(&a[midi], &a[begin]);

	int key = a[begin];
	int hole = begin;
	while (begin < end)
	{
		// 右边找小,填到左边的坑
		while (begin < end && a[end] >= key)
		{
			--end;
		}

		a[hole] = a[end];
		hole = end;

		// 左边找大,填到右边的坑
		while (begin < end && a[begin] <= key)
		{
			++begin;
		}

		a[hole] = a[begin];
		hole = begin;
	}

	a[hole] = key;
	return hole;
}
void QuickSort(int* a, int begin, int end)
{
	if (begin >= end)
		return;

	int keyi = PartSort2(a, begin, end);
	QuickSort(a, begin, keyi - 1);
	QuickSort(a, keyi+1, end);
}
2.3.2.3 前后指针版本
int PartSort3(int* a, int begin, int end)
{
	int midi = GetMidi(a, begin, end);
	Swap(&a[midi], &a[begin]);
	int keyi = begin;

	int prev = begin;
	int cur = prev + 1;
	while (cur <= end)
	{
		if (a[cur] < a[keyi] && ++prev != cur)
			Swap(&a[prev], &a[cur]);

		++cur;
	}

	Swap(&a[prev], &a[keyi]);
	keyi = prev;
	return keyi;
}
void QuickSort(int* a, int begin, int end)
{
	if (begin >= end)
		return;

	int keyi = PartSort3(a, begin, end);
	QuickSort(a, begin, keyi - 1);
	QuickSort(a, keyi+1, end);
}

2.3.3 快速排序优化以及快速排序非递归

  1. 三数取中法选key
  2. 递归到小的子区间时,可以考虑使用插入排序
//void QuickSort(int* a, int begin, int end)
//{
//	if (begin >= end)
//		return;
//
//	if (end - begin + 1 <= 10)
//	{
//		InsertSort(a + begin, end - begin + 1);
//	}
//	else
//	{
//		int midi = GetMidi(a, begin, end);
//		Swap(&a[midi], &a[begin]);
//
//		int left = begin, right = end;
//		int keyi = begin;
//
//		while (left < right)
//		{
//			// 右边找小
//			while (left < right && a[right] >= a[keyi])
//			{
//				--right;
//			}
//
//			// 左边找大
//			while (left < right && a[left] <= a[keyi])
//			{
//				++left;
//			}
//
//			Swap(&a[left], &a[right]);
//		}
//
//		Swap(&a[left], &a[keyi]);
//		keyi = left;
//
//		// [begin, keyi-1] keyi [keyi+1, end]
//		QuickSort(a, begin, keyi - 1);
//		QuickSort(a, keyi + 1, end);
//	}
//}
void QuickSortNonR(int* a, int begin, int end)
{
	ST s;
	STInit(&s);
	STPush(&s, end);
	STPush(&s, begin);

	while(!STEmpty(&s))
	{
		int left = STTop(&s);
		STPop(&s);
		int right = STTop(&s);
		STPop(&s);

		int keyi = PartSort3(a, left, right);
		// [left, keyi-1] keyi [keyi+1, right]
		if (left < keyi - 1)
		{
			STPush(&s, keyi - 1);
			STPush(&s, left);
		}

		if (keyi + 1 < right)
		{
			STPush(&s, right);
			STPush(&s, keyi+1);
		}
	}

	STDestroy(&s);
}

快速排序的特性总结:

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

2.4 归并排序

基本思想:
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide andConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。 归并排序核心步骤
排序的概念以及几种基本常用排序,排序算法,算法

归并排序的特性总结:
5. 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
6. 时间复杂度:O(N*logN)
7. 空间复杂度:O(N)
8. 稳定性:稳定

2.5 非比较排序(计数排序)

// 计数排序
// 时间:O(N+range)
// 空间:O(range)
void CountSort(int* a, int n)
{
	int min = a[0], max = a[0];
	for (int i = 1; i < n; i++)
	{
		if (a[i] < min)
			min = a[i];

		if (a[i] > max)
			max = a[i];
	}

	int range = max - min + 1;
	int* count = (int*)calloc(range, sizeof(int));
	if (count == NULL)
	{
		printf("calloc fail\n");
		return;
	}

	// 统计次数
	for (int i = 0; i < n; i++)
	{
		count[a[i] - min]++;
	}

	// 排序
	int i = 0;
	for (int j = 0; j < range; j++)
	{
		while (count[j]--)
		{
			a[i++] = j + min;
		}
	}
}

思想:计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用。 操作步骤:

  1. 统计相同元素出现次数
  2. 根据统计的结果将序列回收到原来的序列中排序的概念以及几种基本常用排序,排序算法,算法计数排序的特性总结:
    1, 计数排序在数据范围集中时,效率很高,但是适用范围及场景有限。
    2.时间复杂度:O(MAX(N,范围))
  3. 空间复杂度:O(范围)
  4. 稳定性:稳定

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

排序的概念以及几种基本常用排序,排序算法,算法
排序的概念以及几种基本常用排序,排序算法,算法文章来源地址https://www.toymoban.com/news/detail-797015.html

到了这里,关于排序的概念以及几种基本常用排序的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 常见的几种排序算法

    目录 一、插入排序 1、直接插入排序 1.1、排序方法 1.2、图解分析 1.3、代码实现 2、希尔排序 2.1、排序方法 2.2、图解分析 2.3、代码实现 二、选择排序 1、直接选择排序 1.1、排序方法 1.2、图解分析 1.3、代码实现 2、堆排序 2.1、排序方法 2.2、图解分析 2.3、代码实现 三、交换

    2024年02月09日
    浏览(45)
  • Jmeter —— 常用的几种断言方法(基本用法)

    在使用JMeter进行性能测试或者接口自动化测试工作中,经常会用到的一个功能,就是断言,断言相当于检查点,它是用来判断系统返回的响应结果是否正确,以此帮我们判断测试是否通过,本文 主要介绍几种常用的断言:响应断言、JSON断言、BeanShell 断言 1. 响应断言是最常用

    2024年02月08日
    浏览(40)
  • 模板匹配相关概念与几种不常用的模板匹配(学都学了,了解一下)

    模板匹配指的是通过模板图像与测试图像之间的比较,找到测试图像上与模板图像相似的部分,这是通过计算模板图像与测试图像中目标的相似度来实现的,可以快速地在测试图像中定位出预定义的目标 是图像处理中最基本、最常用的匹配方法 为感兴趣的对象 创建模型 :使

    2024年02月08日
    浏览(41)
  • 【一起学数据结构与算法】几种常见的排序(插入排序、选择排序、交换排序、归并排序)

    排序是计算机内经常进行的一种操作,其目的是将一组 “无序” 的记录序列调整为 “有序” 的记录序列。分 内部排序 和 外部排序 ,若整个排序过程不需要访问外存便能完成,则称此类排序问题为内部排序。反之,若参加排序的记录数量很大,整个序列的排序过程不可能

    2023年04月09日
    浏览(44)
  • 【数据结构】- 排序(详细介绍几种排序算法!!!*直接插入排序,*希尔排序,*选择排序,*堆排序,*冒泡排序,*快速排序,*归并排序)

    排序无处不在,所谓排序,就是使一串记录,按照其中的某个或某些的大小,递增或递减的排列起来的操作。 内部排序 :数据元素全部放在内存中的排序。 外部排序 :数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。 今天

    2024年01月20日
    浏览(59)
  • 【排序算法】一、排序概念和直接插入排序(C/C++)

    「前言」文章内容是排序算法之 直接插入排序 的讲解。(所有文章已经分类好,放心食用) 「归属专栏」排序算法 「主页链接」个人主页 「笔者」枫叶先生(fy) 排序的概念 排序 :所谓排序,就是使一串记录,按照其中的某个或某些的大小, 递增或递减 的排列起来

    2024年01月22日
    浏览(40)
  • Zookeeper的基本概念以及安装

            Zookeeper是一个分布式的(多台机器同时干一件事情),开源的分布式应用程序协调服务,是Google公司Chubby产品,是Hadoop和Base重要的组件,.它是一个分布式应用程序提供一致性的服务的软件,提供的功能包括:配置服务,域名服务,分布式同步,组服务等         Zookeeper目标封

    2024年02月15日
    浏览(47)
  • Flink的简介以及基本概念

    有界流和无界流 有状态的流处理 2.1集群角色 2.2 部署模式 会话模式(Session Mode) 单作业模式(Per-Job Mode) 应用模式(Application Mode) 3.1  系统架构 1 )作业管理器(JobManager) JobManager是一个Flink集群中任务管理和调度的核心,是控制应用执行的主进程。也就是说,每个应用

    2024年04月09日
    浏览(57)
  • 记录一下redis基本概念和常用场景

    Redis(Remote Dictionary Server)是一个开源的内存数据库,也可以称为键值存储系统 特点 内存存储 Redis将数据存储在内存中,以提供快速读写访问。这使得Redis非常适合缓存、高速读写操作和计数器等场景。 键值存储 Redis使用键值对的方式来存储数据,其中键是唯一的标识符,而

    2024年02月13日
    浏览(57)
  • ElasticSearch 核心概念以及常用命令

    概念: 这里可以类比与 MySQL 中的表,但是不同于表 在 es 中索引有三层含义 表示源文件数据:通常说集群中有 user 索引,即表示集群服务中存在 user 这样一张“表” 表示索引文件:以加速查询检索为目的而设计和创建的数据文件,通常承载于某些特定的数据结构,如哈希、

    2024年03月10日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包