day07 堆排序的基本实现

前言

我们已经学习了堆的插入和删除操作,下面我们来学习一下堆排序

其实堆排序很简单,主要有两种实现方法:

方法一:

将元素依次插入到堆中,然后输出堆,此时输出的元素都是有序的。这种方法利用的是堆的特性,因为非常简单,我就不进行代码展示了。

 

方法二:

 

将一个数据源数组传给堆,堆在初始化的时候会把数组的元素依次复制到堆内部数组中,但是注意,此时堆的数据是无需的,那么如何排序呢?就是从第一个不是叶子的节点节点开始,依次进行shitDown操作。

为什么要这么操作呢?为什么要只对非叶子节点进行操作呢?因为叶子是没有子孩子,所以叶子节点可以看成是一个只有一个元素的二叉树,它是有序的。所以我们不需要进行考虑。

那么如何找到第一个非叶子节点呢?当根元素的下标为1的情况下,第一个非叶子节点的下标为 count / 2 ,利用这个规律,我们就可以进行操作了。

没什么难度。大家看一下源码就行了

代码实现

方法二代码:

/*
	 * 二叉堆的构造函数
	 * int [] arr,数据源数组
	 * int size,堆的容量大小
	 * */
	public Heap(int [] arr,int size) {
		if(size <= 0) {
			throw new RuntimeException("size can not be null !");
		}
		int len = arr.length;
		datas = new int [size+1];
		for(int i = 0;i < len;i++) {
			datas[i+1] = arr[i];
		}
		count = len;
		for(int i = count/2;i >= 1;i--) {
			shitDown(i);
		}
	}

完整代码实现

package com.smarking.lzy.part2;

import com.smarking.lzy.part1.SortTestHelper;

/*
 * 用数组实现堆
 * 堆的定义?
 * 二叉堆左右节点和父节点之间的关系?
 * 如何使用数组进行是实现?
 * 
 * 
 * */
public class Heap {
	//定义一个数组用来存储数据
	private int [] datas;
	//定义一个变量来记录当前数据的数量
	private int count;
	
	/*
	 * 二叉堆的构造函数
o	 * int size : 堆的大小
	 * */
	public Heap(int size) {
		if(size <= 0) {
			throw new RuntimeException("size can not be null !");
		}
		count = 0;
		datas = new int [size];
	}
	
	/*
	 * 二叉堆的构造函数
	 * int [] arr,数据源数组
	 * int size,堆的容量大小
	 * */
	public Heap(int [] arr,int size) {
		if(size <= 0) {
			throw new RuntimeException("size can not be null !");
		}
		int len = arr.length;
		datas = new int [size+1];
		for(int i = 0;i < len;i++) {
			datas[i+1] = arr[i];
		}
		count = len;
		for(int i = count/2;i >= 1;i--) {
			shitDown(i);
		}
	}
	
	//获取当前堆的大小
	public int size() {
		if(datas == null) {
			throw new RuntimeException("Heap is null !");
		}else {
			return count;
		}
	}
	
	//判断是否为空
	public boolean isEmpty() {
		if(datas == null || datas.length == 0) {
			return true;
		}else {
			return false;
		}
	}
	
	//最大堆的插入操作
	public void insert(int value) {
		if(count >= datas.length - 1) {
			throw new RuntimeException("Heap is full !");
		}
		
		datas[count+1] = value;
		count+=1;
		
		//对count位置的元素进行调整
		shitUp(count);
	}
	
	/**
	 * 对指定位置的元素进行重新调整,使其能够符合最大堆的定义
	 * 原理:不断和它的父节点比较,如果都比它大,就退出。反之,则进行交换,然后重复操作
	 * */
	private  void shitUp(int index) {
		while(index > 1 && datas[index/2] < datas[index]) {
			int val = datas[index];
			datas[index] = datas[index/2];
			datas[index/2] = val;
			index = index/2;
		}
	}
	
	//弹出最大元素
	public int delete() {
		int result = datas[1];
		datas[1] = datas[count];
		count-=1;
		shitDown(1);
		return result;
	}
	
	/**
	 * 对指定位置的元素进行重新调整,使其能够符合最大堆的定义
	 * 原理:不断和它的左右孩子比较,如果都比它小,就退出。反之,则选择一个最大的进行交换,然后重复操作
	 * */
	private void shitDown(int index) {
		//假如左节点还存在,就循环
		while(index*2 <= count) {
			int j = index*2;
			//判断是否有右孩子,然后判断是否符合交换条件
			if(j+1 <= count && datas[j+1] > datas[j]) {
				if(datas[index] > datas[j+1]) {
					return;
				}
				int val = datas[j+1];
				datas[j+1] = datas[index];
				datas[index] = val;
				j += 1;
			}else {
				if(datas[index] > datas[j]) {
					return;
				}
				
				int val = datas[j];
				datas[j] = datas[index];
				datas[index] = val;
			}
			
			index = j;
		}
	}
	
	
	public void printHeap() {
		if(isEmpty()) {
			throw new RuntimeException("Heap is null !");
		}
		
		for(int i = 1;i <= count;i++) {
			System.out.println("index:"+i+";value:"+datas[i]);
		}
	}
	
	public static void main(String[] args) {
		int testTime = 1000;
		int maxValue = 100;
		int maxSize = 10000;
		boolean success = true ;
		Heap heap = null;
		for(int i = 0;i < testTime;i++) {
			int [] arr1 = SortTestHelper.generateRandomArray(maxSize, maxValue);
			int [] arr2 = SortTestHelper.copyArray(arr1);
			int [] arr3 = SortTestHelper.copyArray(arr1);
			heap = new Heap(arr1,arr1.length);
			SortTestHelper.comparator(arr2);
			if(!SortTestHelper.isEqual(arr2, heap)) {
				success = false;
				SortTestHelper.printArray(arr1);
				break;
			}
		}
		
		if(success) {
			System.out.println("Nice!!!");
		}else {
			System.out.println("Fuck!");
		}
	}
}

 

上一篇:字符编码


下一篇:渐进式web应用开发---ajax本地数据存储(四)