堆排序-Java小顶堆排序

二叉堆满足二个特性:
 1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。
2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。
 当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆。
 3.二叉堆是完全二叉树
节点数为n,叶子个数为(n+1)/2,所以非结点数为(n-1)/2

堆排序实现过程图解:以数组{9,7,6,1,2,8,5}为例

首先根据该数组元素构建一个完全二叉树,得到:

               9      

   7                    6

1      2           8      5

 然后需要构造初始堆,则从最后一个非叶节点开始调整,调整过程如下:

6,8,5中5最小,5与顶6互换,5作为顶:

               9                        同理对7也一样            |               9                           同理对9,1,5也一样            |               1                                

   7                    5              1,7互换                      |   1                    5                 1,9互换                            |   9                    5                        

1      2           8     6                                                 |7      2           8      6                                                         |7      2           8      6           

9和1交换后导致9不满足堆的性质,所以自上向下,重新调整,2与9互换。

              1                                   

   2                    5                                     

7      9          8      6                                               

这样就得到了初始堆。

即每次调整都是从父节点、左孩子节点、右孩子节点三者中选择最小者跟父节点进行交换(交换之后可能造成被交换的孩子节点不满足堆的性质,因此每次交换之后要重新对被交换的孩子节点进行调整)。
然后针对初始堆,排序。
1:堆顶与最后一个节点互换,然后针对新堆的6个节点,,自顶向下重新调整成小顶堆

               6                        对6,2,5调整                  |               2                       一直调整,所针对的节点的编号(从零开始)              

   2                    5              6,2互换                      |   6                    5             的子节点>=堆的节点6                

7      9           8     1                                                 |7      9           8      1                

2:然后重复1步骤

              8                        一直调整                       |               5                       一直调整,所针对的节点的编号(从零开始)              

   6                    5                                                    |   6                    8             的子节点>=堆的节点6                

7      9               1                                                 |7      9           2      1                

最后排好序

               9      

   8                    7

6      5           2      1

Java代码实现:

package myheapsort;

import java.util.Scanner;
/*
 * 二叉堆满足二个特性:
 * 1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。
 * 2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。
 * 当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆。
 * 3.二叉堆是完全二叉树
 * 节点数为n,叶子个数为(n+1)/2,所以非结点数为(n-1)/2
 */
/**
 * 小顶堆排序
 * @author wjh
 */
public class MyMinHeapSort {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int[] a = new int[100];
		int n = 0;
		Boolean flag = true ;
		while(flag){
			try{
				System.out.println("输入数组:如 1,2,3");
				String str = sc.next().trim();
				if(str.indexOf(",")==0||str.lastIndexOf(",")==str.length()-1)
					continue;
				String[] strArr = str.split(",");
				n = strArr.length;
				if(n>a.length)
					continue;
				for(int i = 0; i< strArr.length ; i++)
					a[i] = new Integer(strArr[i]);
				flag = false;
			}catch(Exception e){
				System.out.println("不合格式,数组格式:1,2,3");
			}
		}
		sc.close();
		System.out.print("      原数组: ");
		arrayToString(a, n);
		
		//将数组转化成小顶堆
		a = makeMinHeap(a, n);
		System.out.print("变成小顶堆数组: ");
		arrayToString(a, n);
		//将小顶堆,将堆顶与最后的元素互换,节点书减1,然后重新转化成小顶堆,直至堆中没有元素
		for(int i = n; i>1; i--){
			a = minHeapDeleteNumber(a, i);
		}
		System.out.print(" 完成排序数组: ");
		arrayToString(a, n);
	}
	
	/* 堆的删除 按定义:
	 * 堆中每次都只能删除第0个数据。
	 * 为了便于重建堆,实际的操作是将最后一个数据的值赋给根结点,
	 * 然后再从根结点开始进行一次从上向下的调整。
	 * 调整时先在左右儿子结点中找最小的,
	 * 如果父结点比这个最小的子结点还小说明不需要调整了,
	 * 反之将父结点和它交换后再考虑后面的结点。
	 * 相当于从根结点将一个数据的“下沉”过程。*/
	/**
	 * 删除小顶堆的堆顶,重新自顶向下,重新建成小顶堆
	 * @param a 小顶堆数组
	 * @param n 节点个数
	 * @return 小顶堆数组
	 */
	public static int[] minHeapDeleteNumber(int a[], int n)  
	{  
		//将a[0]与a[n-1]互换
		int temp = a[0];
		a[0] = a[n-1];
		a[n-1] = temp;
		
		//节点个数-1
	    return minHeapFixdown(a,0,n - 1);
	}
	/**
	 * 将以编号i为根节点的子树变成符合小顶堆性质
	 * @param a 数组
	 * @param i 父节点
	 * @param n 节点个数
	 * @return 小顶堆数组
	 */
	public static int[] minHeapFixdown(int[] a,int i, int n){
		if(n==1) return a;
		int f_node = i;
		//做孩子节点
		int c_node = f_node*2+1;
		//直至孩子节点编号<节点数n,不断循环
		while(c_node<n){
			int temp = a[f_node];
			
			//如果右节点存在且比左节点小,将childNode变为右子节点的编号
			//孩子节点转化为有孩子节点
			if(c_node+1<n&&a[c_node+1]<a[c_node])
				c_node++;
			//如果孩子节点大于父节点,停止
			if(a[c_node]>=temp)
				break;
			//父节点取孩子节点的值
			a[f_node] = a[c_node];
			a[c_node] = temp;
			//以该孩子节点为父节点
			f_node = c_node;
			c_node = f_node*2+1;
		}
		return a;
	}
	/**
	 * 将数组化成二叉堆
	 * @param a
	 * @param n
	 * @return
	 */
	public static int[] makeMinHeap(int[] a, int n){
		for(int i = n/2-1; i>=0;i--)
			a = minHeapFixdown(a,i,n);
		return a;
	}
	public static void arrayToString(int[] a, int n){
		String s = "";
		for(int i = 0; i<n; i++){
			s = s+a[i]+",";
		}
		s = s.substring(0, s.length()-1);
		System.out.println(s);
	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值