树形结构----最大堆

1. 最大堆的定义:二叉堆是一颗完全二叉树( 区别于满二叉树 ),堆中某个结点的值总是不大于其父节点的值,通常这种堆称为最大堆( 相应的可以定义最小堆 )下层的某一元素不一定小于上层的某一元素

2. 最大堆的存储结构:既然是完全二叉树,所以可以用数组定义该结构。

如图就是一个最大堆:树形结构----最大堆_第1张图片

3. 最大堆中的节点关系:因为是通过数组进行存储的,所以节点的角标就对应数组中的角标。

        1>. 父节点角标:( 子节点角标 - 1 ) / 2。即" parent = ( i - 1 ) / 2 "。

        2>. 左孩子角标:父节点角标 * 2 + 1。即" leftChild = 2 * i + 1 "。

        3>. 右孩子角标:父节点角标 * 2 + 2。即" rightChild = 2 * i + 2 "。

4. 堆接口的定义:

public interface Heap extends Iterable{
	//获取最大堆中的有效元素个数
	public int size();
	//判断最大堆是否为空
	public boolean isEmpty();
	//清空最大堆
	public void clear();
	//向最大堆中添加元素
	public void add(E element);
	//删除最大堆中的最大值
	public E extractMax();
	//查找最大堆中的最大值
	public E findMax();
	//查找最大堆中的最小值
	public E findMin();
	//修改最大堆中的元素
	public E replace(E element);
}

5. 最大堆的实现:

//定义最大堆
/*
* 最大堆的特点是任意节点都比其左右孩子节点大 因此最大堆中的节点都应具有可比性
* 我们在底层使用数组ArrayList实现最大堆
* 最大堆是一种完全二叉树
* 最大堆中的父节点角标和子节点角标中存在关系:
* 父节点角标:(子节点角标-1)/2
* 左子节点角标:父节点角标*2+1
* 右子节点角标:父节点角标*2+2
* 我们在对最大堆进行添加操作时 每添加一个元素都应进行最大堆的转换 使用元素上浮进行最大堆的转换
* 在对最大堆进行删除和修改时 每操作一个元素同样都应进行最大堆的转换 使用元素下沉进行最大堆的转换
*/
public class MaxHeap> implements Heap{
	
	ArrayList data = new ArrayList();

	//获取指定角标元素的父节点角标
	private int parent(int index) {
		if(index == 0) {
			throw new IllegalArgumentException("no parent");
		}
		return (index - 1) / 2;
	}

	//获取指定角标元素的左孩子节点的角标
	private int leftChild(int index) {
		return index * 2 + 1;
	}
	
	//获取指定角标元素的右孩子节点的角标
	private int rightChild(int index) {
		return index * 2 + 2;
	}
	
	//对指定角标处的元素进行上浮操作
	/*
	 * 如果要添加的元素有父元素 并且 父元素小于要添加的元素
	 * 就交换父元素和要添加元素的位置
	 * 要添加元素的角标更新为父元素的角标
	 * 循环以上上浮操作 直至要添加的元素没有有父元素 或者 父元素大于要添加的元素
	 */
	private void siftUp(int k) {
		while(k > 0 && data.get(k).compareTo(data.get(parent(k))) > 0) {
			data.swap(k, parent(k));
			k = parent(k);
		}
	}
	
	//下沉最大堆中指定角标的元素
	/*
	 * 如果当前角标的元素有左右孩子 并且 当前角标的元素小于左后孩子中大的
	 * 就将左右孩子中大的与当前角标元素交换位置
	 * 更新当前元素角标为左右孩子中大的孩子的角标
	 * 循环以上下沉操作 直至当前角标的元素没有孩子 或者 当前角标的元素大于其左右孩子
	 */
	private void siftDown(int k) {
		//如果没有左孩子 同时也就没有右孩子 就不用下沉
        //如果有左孩子 右孩子不一定存在 判断右孩子的存在性
        //如果右孩子存在 取左右两个孩子的最大值和k对应的值比较
        //如果右孩子不存在 只能取左孩子的值和k对应的值比较
        //如果k对应的值比左右两个孩子都大 则不用下沉 否则下沉即可
		while(leftChild(k) < data.size()) {
			int j = leftChild(k);
			if(j + 1 < data.size() && data.get(j).compareTo(data.get(j + 1)) < 0) {
				j = rightChild(j);
			}
			if(data.get(k).compareTo(data.get(j)) < 0) {
				data.swap(k, j);
				k = j;
			}else {
				break;
			}
		}
	}
	
	//获取最大堆中的有效元素个数
	@Override
	public int size() {
		return data.size();
	}

	//判断最大堆是否为空
	@Override
	public boolean isEmpty() {
		return data.isEmpty();
	}

	//清空最大堆
	@Override
	public void clear() {
		data.clear();
	}

	//向最大堆中添加元素
	//每添加一个元素都应进行最大堆的转换 使用元素上浮进行最大堆的转换
	@Override
	public void add(E element) {
		data.add(element);
		siftUp(data.size() - 1);
		
	}

	//删除最大堆中的最大值
	//每删除一个元素同样都应进行最大堆的转换 使用元素下沉进行最大堆的转换
	@Override
	public E extractMax() {
		if (data.isEmpty()) {
            throw new IllegalArgumentException("maxheap is empty");
        }
		E max = findMax(); //获取最大堆中的最大值
		data.swap(0, data.size() - 1); //交换最大值和最大堆末尾元素的位置
		data.remove(data.size() - 1); //删除最大堆末尾元素(这样删除最大堆的最大元素是时间复杂度为O(1))
		siftDown(0); //下沉最大堆根节点的元素
		return max;
	}

	//查找最大堆中的最大值 即二叉堆中的根节点 数组中的首元素
	@Override
	public E findMax() {
	    if (data.isEmpty()) {
            throw new IllegalArgumentException("maxheap is empty");
        }
		return data.get(0);
	}

	//查找最大堆中的最小值
	@Override
	public E findMin() {
		if (data.isEmpty()) {
            throw new IllegalArgumentException("maxheap is empty");
        }
		E min = data.get(0);
		for(int i = 1; i < data.size(); i++) {
			if(data.get(i).compareTo(min) < 0) {
				min = data.get(i);
			}
		}
		return min;
	}

	//修改最大堆中的元素
	//每修改一个元素同样都应进行最大堆的转换 使用元素下沉进行最大堆的转换
	@Override
	public E replace(E element) {
		E max = findMax();
		data.set(0, element);
		siftDown(0);
		return max;
	}

	//格式化最大堆的输出格式
	@Override
	public String toString() {
		return data.toString();
	}
	
	//迭代最大堆 即迭代ArrayList
	@Override
	public Iterator iterator() {
		return data.iterator();
	}
}

6. 最大堆代码测试:

public class TestMaxHeap {
	public static void main(String[] args) {
        MaxHeap heap = new MaxHeap<>();
        heap.add(3);
        heap.add(5);
        heap.add(1);
        heap.add(2);
        heap.add(6);
        heap.add(4);
        heap.add(7);
        System.out.println(heap);
        System.out.println(heap.extractMax());
        System.out.println(heap);
	}
}

7. 运行结果:

树形结构----最大堆_第2张图片

 

你可能感兴趣的:(Java数据结构与算法,数据结构,java,树形结构)