数据结构第六课 -----排序

这篇具有很好参考价值的文章主要介绍了数据结构第六课 -----排序。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

作者前言

🎂 ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂
​🎂 作者介绍: 🎂🎂
🎂 🎉🎉🎉🎉🎉🎉🎉 🎂
🎂作者id:老秦包你会, 🎂
简单介绍:🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂
喜欢学习C语言和python等编程语言,是一位爱分享的博主,有兴趣的小可爱可以来互讨 🎂🎂🎂🎂🎂🎂🎂🎂
🎂个人主页::小小页面🎂
🎂gitee页面:秦大大🎂
🎂🎂🎂🎂🎂🎂🎂🎂
🎂 一个爱分享的小博主 欢迎小可爱们前来借鉴🎂


直接插入排序

数据结构第六课 -----排序,数据结构
数据结构第六课 -----排序,数据结构

数据结构第六课 -----排序,数据结构

思路: 我们要记得[0,end]是有序的,我们要把tmp的值插入到[0,end]就要进行判断,直到tmp等于数组的长度结束,这个过程中我们要注意到我们把tmp插入到[0,end] 是要遍历[0,end]的当我们判断当前的元素大于tmp,就把这个元素往后移动,我们就要往后一个元素比较,直到碰见比tmp小的元素,并再该元素后面插入,如果碰见了在[0,end]都没有小于tmp的元素,我们就要在下标为0的地方插入,

void InsertSort(int* a, int n)
{
	//[0,end] 
	int i = 0;
	for (i = 0; i < n-1; i++)
	{
		int end = i;
		int tmp = a[end + 1];
		while (end >= 0)
		{
			if (a[end] > tmp)
			{
				//往后移动
				a[end + 1] = a[end];
				end--;
			}
			else
			{
				break;
			}
		}
		//这个写法一箭双雕,一来可以防止end为-1的情况不用去判断,二来可以插入到a[end + 1]
		a[end + 1] = tmp;
	}
}

冒泡排序

数据结构第六课 -----排序,数据结构

// 冒泡排序
void Bubblisort(int* a, int n)
{
	int i = 0; 
	for (i = 0; i < n - 1; i++)
	{
		//如果该数组是一个有序数组,只需遍历一遍下面的就可以了,时间复杂度为O(N)
		bool excheng = false;
		int j = 0;
		for (j = 0; j < n - 1 - i; j++)
		{
			if (a[j] > a[j + 1])
			{
				int c = a[j];
				a[j] = a[j + 1];
				a[j + 1] = c;
				excheng = true;
			}
		}
		if (excheng == false)
			break;
	}
}

时间复杂度是O(N^2), 最好的情况就是O(N)

希尔排序

数据结构第六课 -----排序,数据结构

分成两步:
1.预排序 (接近有序)
2.直接插入排序
思路:
数据结构第六课 -----排序,数据结构
相同颜色的框进行插入排序,因为多少种颜色是有gap的数值决定的,每一种颜色对应的是整个数组的一部分

//预排序
	int gap = 3;
	int i = 0;
	//有gap个数组
	for (i = 0; i < gap; i++)
	{
		//每个数组进行插入排序
		int sub = i;
		while (sub <= n - 1 - gap)
		{
			int end = sub;
			int top = a[end + gap];
			while (end >= 0)
			{
				if (top < a[end])
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
					break;
			}
			a[end + gap] = top;
			sub += gap;
		}
	}

上面这种是一组组进行插入排序.如果是多组进行插入排序

数据结构第六课 -----排序,数据结构
思路就是我们仍然采用上面的方法,但是我们是多组进行插入排序,仍然是相同颜色的进行插入排序

//预排序
	int gap = 3;
	int i = 0;
	//有gap个数组
	for (i = 0; i <= n - 1 - gap; i++)
	{
		//每个数进行插入排序
		
		int end = i;
		int top = a[end + gap];
		while (end >= 0)
		{
			if (top < a[end])
			{
				a[end + gap] = a[end];
				end -= gap;
			}
			else
				break;
		}
		a[end + gap] = top;
			
	}

预排序的特点:
gap越大,大的值更快调到后面,小的值可以更快的调到前面,越不接近有序
gap越小,跳得越慢,但是越接近有序,如果gap == 1就是直接插入排序

最终代码为

//希尔排序
void ShellSort(int* a, int n)
{
	//预排序
	int gap = 3;
	int i = 0;
	//有gap个数组
	for (i = 0; i <= n - 1 - gap; i++)
	{
		//每个数进行插入排序
		
		int end = i;
		int top = a[end + gap];
		while (end >= 0)
		{
			if (top < a[end])
			{
				a[end + gap] = a[end];
				end -= gap;
			}
			else
				break;
		}
		a[end + gap] = top;
			
	}
	//直接插入排序
	InsertSort(a, n);
}

但是我们可以简化一下
我们可以抓住gap=1为直接插入排序

//希尔排序
void ShellSort(int* a, int n)
{
	//预排序
	int gap = n;
	while (gap > 1)
	{
		//一来gap等于1时,就是直接插入排序,二来就是gap是随n增大的,
		//再还有就是gap越小,就越接近有序
		gap = gap / 3 + 1;
		int i = 0;
		//有gap个数组
		for (i = 0; i <= n - 1 - gap; i++)
		{
			//每个数进行插入排序

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

		}
	}
	
}

数据结构第六课 -----排序,数据结构
时间复杂度O(N ^1.3),这个有点难算,我们只需要理解大概就行

直接选择排序

数据结构第六课 -----排序,数据结构
思路:从开头开始找,找到最小的,然后进行和开头交换,然后再从剩下的后面继续寻找最小的,依次往后插入
思路图1:这个思路是很多人能想出来的

数据结构第六课 -----排序,数据结构
思路图2:

数据结构第六课 -----排序,数据结构

​这里我是使用了两边,左边插入最小的,右边插入最大的,插入好后,begin往前 ,end往后,直到begin等于end,就停止了

void excheng(int* a, int* b)
{
	int c = *a;
	*a = *b;
	*b = c;
}
//直接选择排序
void SelectSrot(int* a, int n)
{
	int min = 0, max = 0; //找出最大和最小
	int begin = 0, end = n - 1;// 在最大和最小的位置插入
	for (int i = begin + 1; i <= end; i++)
	{
		int idx = i;
		while (idx <= end)
		{
			//找出最小的值
			if (a[min] > a[idx])
				min = idx;
			//找到最大值
			if (a[max] < a[idx])
				max = idx;
			idx++;
		}
		excheng(&a[begin], &a[min]);
		//防止开头就是最大值,一旦最小值交换,就乱了
		if (max == begin)
			max = min;
		excheng(&a[end], &a[max]);
		begin++;
		end--;

	}
}

时间复杂度是 O(N^2)

堆排序

大家可以观看这部博客
堆排序
数据结构第六课 -----排序,数据结构

//堆排序
typedef int Heapdata;
void exchange(Heapdata* a, Heapdata* b)
{
	Heapdata e = *a;
	*a = *b;
	*b = e;
}
void Heapsort(Heapdata* heap, int size)
{
	//建大堆
	int i = 0;
	for (i = 1; i < size; i++)
	{
		//向上调整
		int child = i;
		int parent = (child - 1) / 2;
		while (child > 0)
		{
			if (heap[child] > heap[parent])
			{
				//交换
				exchange(&heap[child], &heap[parent]);
				child = parent;
				parent = (child - 1) / 2;
			}
			else
				break;
		}

	}
	//开始升序排序
	while (size > 0)
	{
		// 根节点和最后一个叶节点交换
		exchange(&heap[0], &heap[--size]);
		//向下调整
		int parent = 0;
		int child = parent * 2 + 1;
		while (child < size)
		{
			if (child + 1 < size && heap[child] < heap[child + 1])
			{
				child += 1;
			}
			if (heap[child] > heap[parent])
				exchange(&heap[child], &heap[parent]);
			else
				break;
			parent = child;
			child = parent * 2 + 1;
		}
	}



}

快速排序

hoare版本

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止
数据结构第六课 -----排序,数据结构
这个图可能有点简陋
数据结构第六课 -----排序,数据结构
数据结构第六课 -----排序,数据结构
时间复杂度:每一次都会把当前数组的每个元素遍历一遍,然后再把key交换, 需要进行log(n)次递归
时间复杂度是:O(n*log(n))
数据结构第六课 -----排序,数据结构
复杂的话,就如同这个一样,这种情况就是有n层, 时间复杂度就是 1+2+3+…+n, 所以时间复杂度就是O(n^2)

//快速排序
void QuickSrot(int* a, int begin, int end)
{
	//当只有一个元素就不用进行了
	if (begin >= end)
		return;
	int key = begin;
	int left = begin;//这里不能begin加1 否则在遇到有序的时候就会排序出错
	int right = end;
	while (left < right)
	{
		// 找最小
		while (left < right)
		{
			if (a[right] < a[key])
			{
				break;
			}
			right--;
		}

		// 找最大
		while (left < right)
		{
			if (a[left] > a[key])
			{
				break;
			}
			left++;
		}
		
		excheng(&a[right], &a[left]);
	}
	excheng(&a[right], &a[key]);
	//左
	QuickSrot(a, begin, right - 1);
	// 右
	QuickSrot(a, right + 1, end);
}

优化点

三数取中

思路:
我们可以在数组的前后和中间选取中位数,然后把中位数和开头进行交换,

int TriNum(int *a,int begin, int end)
{
	int mid = (begin - end) / 2 + end;
	if (begin > end)
	{
		if (end > mid)
		{
			return end;
		}
		else if(begin < mid)
		{
			return begin;
		}
		return mid;
	}
	else
	{
		if (begin > mid)
		{
			return begin;
		}
		else if (end < mid)
		{
			return end;
		}
		else
			return mid;
	}
}
//快速排序
void QuickSrot(int* a, int begin, int end)
{
	//当只有一个元素就不用进行了
	if (begin >= end)
		return;
	//三数取中
	int key = 0;
	key = TriNum(a, begin, end);
	exchange(&a[begin], &a[key]);
	key = begin;
	int left = begin;
	int right = end;
	//普通方法
	//int key = begin;
	//int left = begin;//这里不能begin加1 否则在遇到有序的时候就会排序出错
	//int right = end;
	while (left < right)
	{
		// 找最小
		while (left < right)
		{
			if (a[right] < a[key])
			{
				break;
			}
			right--;
		}

		// 找最大
		while (left < right)
		{
			if (a[left] > a[key])
			{
				break;
			}
			left++;
		}
		
		excheng(&a[right], &a[left]);
	}

	excheng(&a[right], &a[key]);
	//左
	QuickSrot(a, begin, right - 1);
	// 右
	QuickSrot(a, right + 1, end);
}

小区间优化

当我们在使用快速排序的时候,一直排序知道递归到还剩下该数组的10%的数没有排序,我们如果使用递归就很对栈的空间浪费很大。那我们可以选择使用插入排序,

//快速排序
void QuickSrot(int* a, int begin, int end)
{
	//当只有一个元素就不用进行了
	if (begin >= end)
		return;
	if (end - begin  + 1 <= 10)
	{
		//插入排序
		InsertSort(a + begin, end - begin + 1);//我们要清楚要从哪里开始插入排序
	}
	else
	{
		//三数取中
		int key = 0;
		key = TriNum(a, begin, end);
		excheng(&a[begin], &a[key]);
		key = begin;
		int left = begin;
		int right = end;
		//普通方法,有可能会栈溢出
		//int key = begin;
		//int left = begin;//这里不能begin加1 否则在遇到有序的时候就会排序出错
		//int right = end;
		while (left < right)
		{
			// 找最小
			while (left < right)
			{
				if (a[right] < a[key])
				{
					break;
				}
				right--;
			}

			// 找最大
			while (left < right)
			{
				if (a[left] > a[key])
				{
					break;
				}
				left++;
			}

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

		excheng(&a[right], &a[key]);
		//左
		QuickSrot(a, begin, right - 1);
		// 右
		QuickSrot(a, right + 1, end);
	}
	
}

挖坑法

数据结构第六课 -----排序,数据结构

//挖坑法
void QuickSrot2(int* a, int begin, int end)
{
	if (begin >= end)
		return;
	if (end - begin + 1 <= 10)
	{
		InsertSort(a + begin, end - begin + 1);
	}
	else
	{
		//三数取中
		int key = TriNum(a, begin, end);
		excheng(&a[key], &a[begin]);
		//坑
		key = begin;
		int num = a[key];
		int left = begin;
		int right = end;
		while (left < right)
		{
			//找小
			while (left < right)
			{
				if (a[right] < num)
				{
					a[key] = a[right];
					key = right;
					break;
				}
				right--;
			}
			//找大
			while (left < right)
			{
				if (a[left] > num)
				{
					a[key] = a[left];
					key = left;
					break;
				}
				left++;
			}
		}
		a[key] = num;
		//左
		QuickSrot(a, begin, right - 1);
		// 右
		QuickSrot(a, right + 1, end);

	}
	
	

}

前后指针版本

数据结构第六课 -----排序,数据结构
思路:
cur遇见比key大的值,cur++
cur遇见比key小的值,prev++,交换prev和cur的值交换,然后cur++
数据结构第六课 -----排序,数据结构

//前后指针版本
// 快速排序版本3
void QuickSrot3(int* a, int begin, int end)
{
	if (begin >= end)
		return;
	int key = TriNum(a, begin, end);
	excheng(&a[key], &a[begin]);
	key = begin;
	int prev = begin;
	int cur = begin + 1;
	while (cur <= end)
	{
		//cur 比较
		if (a[cur] < a[key] && ++prev != cur)//增加++prev != cur可以有效解决相同位置进行交换
		{
			exchange(&a[cur], &a[prev]);
		}
		cur++;
	}
	exchange(&a[key], &a[prev]);
	//左
	QuickSrot(a, begin, prev - 1);
	// 右
	QuickSrot(a, prev + 1, end);
}

疑惑

数据结构第六课 -----排序,数据结构文章来源地址https://www.toymoban.com/news/detail-762861.html

  1. 为什么相遇位置比key小
    原因:是right先走
    两种情况:
    (1).R遇见L —>(L和R交换后,R先走)R没有找到比key小的,一直走,直到R遇见L,(特殊情况除外)
    (2)L遇见R----->(R找到小了),然后L没有找到比key大的,一直走,直到L遇见R,(特殊情况除外)

到了这里,关于数据结构第六课 -----排序的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 数据结构:第六章 图

    ps:图不可以为空图。 对于图中的边,两头必须要有结点。 边集是可以没有的,如上图最右边。 关于无向图和有向图的应用如下 比如你微信里的好友关系,你要和一个人建立关系(也就是图的两个结点连上),你只需要加1次就可以了,也不需要你加我,我还要加你。 具体

    2024年02月14日
    浏览(46)
  • 《数据结构》第六章:二叉树

    二叉树是一种递归数据的数据结构。 二叉树(BT) 是含有n(n≥0)个结点的有限结合。当n=0时称为空二叉树。在非空二叉树中: 有且仅有一个称为 根 的结点: 其余结点划分为两个互不相交的子集L和R也是一棵二叉树,分别称为 左二叉树 和 右二叉树。 二叉树有五种基本形

    2024年01月17日
    浏览(46)
  • 《数据结构》王道 第六章 图

    2.1.1 邻接矩阵存储带权图(网) 2.1.2 邻接矩阵的性能分析 2.1.3 邻接矩阵的性质 以此类推,可以得到A 2 的矩阵。 A 3 也是同样的道理,则表示A[i][j] 由 i 到 j 路径长度为3的路径数目。 这种存储图的方法其实跟树的孩子表示法有点相似。 邻接矩阵存储无向图时,一条边会有两

    2024年02月01日
    浏览(45)
  • MySQl数据库第六课-------SQl命令的延续------快来看看

     欢迎小可爱们前来借鉴我的gtiee秦老大大 (qin-laoda) - Gitee.com ———————————————————————————————— SQl语句          数据库操作          数据表操作 SQL增删 ———————————————————————————— 1.主键唯一

    2024年02月16日
    浏览(35)
  • 数据结构 第六章 图——图的遍历

    在前面我们知道,树是一种非线性结构,为了方便它在计算机中的存储,对树进行遍历使它线性化。 而图同样也是一种非线性结构,但是图又是一种不同于树的多对多结构,所以在前面我们将其转换为了多个一对多的结构来描述它的存储结构。 图的遍历同树类似,也是从某

    2024年02月08日
    浏览(46)
  • 算法与数据结构 第六章 图(详解)

    目录 一、判断题 二、选择题  在开始之前,先为大家推荐四篇介绍该章四个主要算法的的文章,供大家参考。 Dijkstra算法求最短路径:Dijkstra算法原理_平凡的L同学的博客-CSDN博客_dijiesitela Floyd算法求最短路径:Floyd算法求最短路径 Prim算法求最小生成树:Prim算法求最小生成树

    2024年02月09日
    浏览(47)
  • 数据结构与算法分析 第六章 图 作业讲解

     参考教材: 《数据结构(C语言版 第2版)》 严蔚敏,李冬梅,吴伟民编著,人民邮电出版社,2022年版。 截图未标明出处均为原创或取自《数据结构(C语言版 第2版)》~   本文对应的作业题讲解视频:   数据结构与算法分析作业讲解视频合集 https://www.bilibili.com/video/BV1N

    2024年02月03日
    浏览(47)
  • 浙大数据结构第六周之初识图

    给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集。假设顶点从0到N−1编号。进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。 输入格式: 输入第1行给出2个整数N(0N≤10)和E,分别是图的顶点数和边数。随后E行,每行给

    2024年02月05日
    浏览(34)
  • Python篇——数据结构与算法(第六部分:哈希表)

      目录 1、直接寻址表 2、直接寻址表缺点 3、哈希 4、哈希表 5、解决哈希冲突 6、拉链法 7、常见哈希函数 8、哈希表的实现 8.1迭代器iter()和__iter__ 8.2str()和repr() 8.3代码实现哈希表 8.4哈希表的应用   直接寻址表:key为k的元素放到k的位置上 改进直接寻址表:哈希(

    2024年02月10日
    浏览(45)
  • 【夜深人静学习数据结构与算法 | 第六篇】贪心算法

    目录 前言: 引入: 贪心算法:     455. 分发饼干 - 力扣(LeetCode) 376. 摆动序列 - 力扣(LeetCode) 53. 最大子数组和 - 力扣(LeetCode) 122. 买卖股票的最佳时机 II - 力扣(LeetCode)         在本文我们将为大家介绍在计算机中比较常见的一种算法:贪心算法。他并没有具体的代

    2024年02月09日
    浏览(53)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包