博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【啊哈!算法】之四、选择排序
阅读量:5132 次
发布时间:2019-06-13

本文共 3053 字,大约阅读时间需要 10 分钟。

选择排序的基本思想是:每一趟从待排序的数据中选出最小元素,顺序放在已排好序的数据最后,直到全部数据排序完毕。

选择排序包括:简单选择排序,堆排序~!

一、简单选择排序

简单选择排序时一种不稳定的算法,他的时间复杂度是:O(n^2),空间复杂度就需要一个中间单元A【0】的空间!

来根据图看一下排序的过程!

根据图大家应该能看出来,算法的思想是:

对于这一组数据,如上面的待排序的数据{K1,K2,…,Kn},首先从数据中寻找最小值,我们假定是Kn , 那么我们要把Kn和K1来交换,就是把最小值移动到最前面,然后从除K1外的剩下的元素去寻找另一个最小值,然后和K2交换,就这样依次类推,直到元素的最后!

OK,来看一下动画演示:

void select_sort(int *a, int N){	int temp;	for(int i = 0; i < N - 1; i++)	{		//寻找最小值		temp = i;		for(int j = i + 1; j < N; j++)		{			if(a[temp] > a[j])			{				temp = j;			}		}		//找到最小后交换数值		if(temp != i)		{			swap(a[temp], a[i]);		}	}}

二、堆排序

堆排序 是一种不稳定算法,他的时间复杂度是:O(nlgn),堆排序不适合于记录数较少的文件,因为建立初始堆比较的次数较多!  他的空间复杂度是O(1)!!

堆是近似于完全二叉树的一种数据结构,他的性质是:

子节点的键值或索引总是小于(大于)它的父节点:

我们的堆通常是通过一维数组来实现的! 可以用树状结构来表示:

也就是:父节点i的左子结点的位置是:(2*i)

父节点i的右子结点的位置是:(2*i+1)

子节点i的父节点的位置是floor(i/2)

ok来看一下:

{1,35,14,60,61,45,15,81}

ok我们下面来看一下堆排序的过程:

给一组数据:{20,12,35,15,10,80,30,17,2,1}(n=10)

初始状态的堆图为:

根据堆得性质可以看书来,上面的堆不是最大堆也不是最小堆!

所以我们要来调整堆!

从后往前查找,自第一个具有孩子的结点开始,根据完全二叉树性质,这个元素在数组中的位置为i=[n/2],如果以这个结点为根的子树已是最大堆,则此时不需调整,否则必须调整子树使之成为堆。随后,继续检查以i-1、i-2等结点为根的子树,直到检查到整个二叉树的根结点(i=1),并将其调整为堆为止。

调整方法:由于A[i]的左、右子树均已是堆,因此A[2i]和A[2i+1]分别是各自子树中关键字最大的结点。若A[i]不小于A[2i]和A[2i+1],则A[i]没有违反堆性质,那么以A[i]为根的子树已是堆,无须调整;否则必须将A[i]和A[2i]与A[2i+1]中较大者(不妨设为A[j])进行交换。交换后又可能使结点A[j]违反堆性质,同样由于该结点的两棵子树仍然是堆,故可重复上述的调整过程,直到当前被调整的结点已满足堆性质,或者该结点已是叶子结点为止。

最终,这组数据经过调整后的最大堆为:{80,17,35,12,10,20,30,15,2,1}!

ok我们再来看一下转换为最小堆,只有最大堆怎么能满足我们呢!

①将建成的最大堆作为初始无序区。

②将堆顶元素(根)A[1]和A[n]交换,由此得到新的无序区A[1..n-1]和有序区A[n],且满足A[1..n-1]≤A[n]

③将A[1..n-1]调整为堆。

④再次将A[1]和无序区最后一个数据A[n-1]交换,由此得到新的无序区A[1..n-2]和有序区A[n-1..n],且仍满足关系A[1..n-2]≤A[n-1..n],同样要将A[1..n-2]调整为堆。直到无序区只有一个元素A[1]为止。

说明:如果需要生成降序序列,则利用最小堆进行操作。

注意:

①堆中任一子树亦是堆。

 ②以上讨论的堆实际上是二叉堆(Binary Heap),类似地可定义k叉堆。

OK,大家来看一下动画演示:

OK,下面来看看代码,先来看一个不递归的:

//*********************************************************//堆排序         这里包括三个函数:// 建堆   Build_Heap    调整堆Heap_ify  排序HeapSort//*********************************************************//建立最大堆调整void Heap_ify(int *a, int i, int size)  //size堆的大小 i 要调整的位置{	//left right 分别是i的左右子节点 largest暂存	for(int left = 2 * i, right = 2 * i + 1, largest = i; left < size || right < size;)	{		if(left < size && a[largest] < a[left])		{			largest = left;		}		if(right < size && a[largest] < a[right])		{			largest = right;		}		if(i != largest)		{			swap(a[largest], a[i]);			//调整节点			i = largest;			left = 2 * i;			right = 2 * i + 1;		}		else		{			break;		}	}}void Build_Heap(int *a, int size){	//从最后一个非叶子节点开始	for(int i = size/2 - 1; i >= 0; i--)	{		Heapify(a, i, size);	}}void HeapSort(int *a, int size){	Build_Heap(a, size);  //建堆	for(int i = size - 1; i > 0; i--)	{		swap(a[0], a[i]);   //堆得第一个元素与之交换		Heapify(a, 0, i);  //调整堆	}}

下面的是对调整的递归版本

//堆调整递归版本void Heapify(int *a, int i, int size){	int left = 2 * i;	int right = 2 * i + 1;	int largest = i;	if(left < size && a[largest] < a[left])	{		largest = left;	}	if(right < size && a[largest] < a[right])	{		largest = right;	}	if(i != largest)	{		swap(a[largest], a[i]);		Heapify(a, largest, size);	}}

2012/8/8

jofranks 于南昌

转载于:https://www.cnblogs.com/java20130723/archive/2012/08/08/3211421.html

你可能感兴趣的文章
mpvue——引入antv-F2图表
查看>>
在UC浏览器打开链接唤醒app,假设没有安装该app,则跳转到appstore下载该应用
查看>>
skozrloug
查看>>
D. Flowers Codeforces Round #271(div2)
查看>>
表单重复提交
查看>>
HDU2767 Proving Equivalences(scc)
查看>>
shell脚本函数与数组
查看>>
HDU - 2825(AC自动机+状态压缩DP(需要优化))
查看>>
论Nim中的 proc 和 method
查看>>
Arch linux配置指南
查看>>
external panel
查看>>
【luogu2667】 超级质数 - DFS
查看>>
Bash快捷键
查看>>
spring相关文档地址
查看>>
happy in java之io流简介
查看>>
第六课 用通配符进行过滤
查看>>
自动代理生成器
查看>>
使用monkey技术修改python requests模块
查看>>
Binary Search Tree analog
查看>>
win7虚拟机MAC系统
查看>>