码迷,mamicode.com
首页 > 编程语言 > 详细

选择排序(直接选择排序、堆排序)——Java

时间:2015-08-21 15:37:35      阅读:227      评论:0      收藏:0      [点我收藏+]

标签:堆排序   选择排序   java   算法   数据结构   

选择排序
思想:每趟从待排序的记录序列中选择关键字最小的记录放置到已排序表的最前位置,直到全部排完。
关键问题:在剩余的待排序记录序列中找到最小关键码记录。
方法:
–直接选择排序
–堆排序

(1)简单的选择排序
  1、基本思想:在要排序的一组数中,选出最小的一个数与第一个位置的数交换;然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。
  
  2、实例
技术分享
实现代码:
	public static void main(String[] args)
	{
		int[] nums={57,68,59,52};
		sort(nums);
	}
	
	public static void sort(int[] nums)
	{
		for (int i = 0; i < nums.length; i++)
		{
			int min=nums[i];
			int n=i;//最小数的索引
			for (int j = i+1; j < nums.length; j++)
			{
				if (nums[j]<min)
				{
					//找出最小数
					min=nums[j];
					n=j;
				}
			}
			nums[n]=nums[i];
			nums[i]=min;
		}
	}

(2)堆排序

1.定义

n个关键字序列Kl,K2,…,Kn称为(Heap),当且仅当该序列满足如下性质(简称为堆性质):
(1)ki<=k(2i)且ki<=k(2i+1)(1≤i≤ n/2),当然,这是小根堆,大根堆则换成>=号。//k(i)相当于二叉树的非叶子结点,K(2i)则是左子节点,k(2i+1)是右子节点
若将此序列所存储的向量R[1..n]看做是一棵完全二叉树存储结构,则堆实质上是满足如下性质的完全二叉树:
技术分享
树中任一非叶子结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。
【例】关键字序列(10,15,56,25,30,70)和(70,56,30,25,15,10)分别满足堆性质(1)和(2),故它们均是堆,其对应的完全二叉树分别如小根堆示例和大根堆示例所示。
大根堆和小根堆:根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最小者的堆称为小根堆,又称最小堆。根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最大者,称为大根堆,又称最大堆。注意:①堆中任一子树亦是堆。②以上讨论的堆实际上是二叉堆(Binary Heap),类似地可定义k叉堆。
堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。
(1)用大根堆排序的基本思想
① 先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区
② 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key
③由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n-2].keys≤R[n-1..n].keys,同样要将R[1..n-2]调整为堆。
……
直到无序区只有一个元素为止。
(2)大根堆排序算法的基本操作:
①建堆,建堆是不断调整堆的过程,从len/2处开始调整,一直到第一个节点,此处len是堆中元素的个数。建堆的过程是线性的过程,从len/2到0处一直调用调整堆的过程,相当于o(h1)+o(h2)…+o(hlen/2) 其中h表示节点的深度,len/2表示节点的个数,这是一个求和的过程,结果是线性的O(n)。
②调整堆:调整堆在构建堆的过程中会用到,而且在堆排序过程中也会用到。利用的思想是比较节点i和它的孩子节点left(i),right(i),选出三者最大(或者最小)者,如果最大(小)值不是节点i而是它的一个孩子节点,那边交互节点i和该节点,然后再调用调整堆过程,这是一个递归的过程。调整堆的过程时间复杂度与堆的深度有关系,是lgn的操作,因为是沿着深度方向进行调整的。
③堆排序:堆排序是利用上面的两个过程来进行的。首先是根据元素构建堆。然后将堆的根节点取出(一般是与最后一个节点进行交换),将前面len-1个节点继续进行堆调整的过程,然后再将根节点取出,这样一直到所有节点都取出。堆排序过程的时间复杂度是O(nlgn)。因为建堆的时间复杂度是O(n)(调用一次);调整堆的时间复杂度是lgn,调用了n-1次,所以堆排序的时间复杂度是O(nlgn)

2、实例

初始序列:46,79,56,38,40,84

  建堆:

技术分享

   交换,从堆中踢出最大数

技术分享



3、代码实现:
	public static void main(String[] args)
	{
		int[] nums={46,79,56,38,40,84};
		int len=nums.length;
		//循环建堆
		for (int i = 0; i < nums.length-1; i++)
		{
			//建堆
			buildMaxHeap(nums,len-1-i);
			//交换堆顶和最后一个元素
			swap(nums,0,len-1-i);
			System.out.println(Arrays.toString(nums));
		}
	}
	
	/**
	 * 对nums数组中0到lastIndex建大顶堆
	 */
	public static void buildMaxHeap(int[] nums,int lastIndex)
	{
		//从lastIndex处节点(最后一个节点)的父节点开始
		for (int i = (lastIndex-1)/2; i >=0; i--)
		{
			//k保存正在判断的节点
			int k=i;
			//如果当前K节点的子节点存在
			while (k*2+1<=lastIndex)
			{
				//k节点的左节点的索引
				int binggerIndex=2*k+1;
				//如果biggerIndex小于lastIndex,即biggerIndex+1代表的k节点的右子节点存在
				if (binggerIndex<lastIndex)
				{
					//如果右子节点的值较大
					if (nums[binggerIndex]<nums[binggerIndex+1])
					{
						binggerIndex++;
					}
				}
				//如果K节点的值小于其较大的子节点的值
				if (nums[k]<nums[binggerIndex])
				{
					//交换他们
					swap(nums, k, binggerIndex);
					//将biggerIndex赋予K,开始While循环的下一次,重新保证k节点的值大于其左右子节点的值
					k=binggerIndex;
				}
				else
				{
					break;
				}	
			}
		}
	}
	
	public static void swap(int[] nums,int i,int j)
	{
		int temp=nums[i];
		nums[i]=nums[j];
		nums[j]=temp;
	}



版权声明:本文为博主原创文章,未经博主允许不得转载。

选择排序(直接选择排序、堆排序)——Java

标签:堆排序   选择排序   java   算法   数据结构   

原文地址:http://blog.csdn.net/zzc8265020/article/details/47834943

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!