1. 程式人生 > >堆其實是個很簡單的資料結構

堆其實是個很簡單的資料結構

 

 

說到堆這種資料結構,很多人的第一反應是感覺很複雜,其實不然,堆就是個優先順序佇列而已,或者,堆其實就是一種樹。本文先講原理,後面給出堆的實現程式碼。

優先順序佇列可以用有序陣列來實現,這種做法的問題是,儘管刪除最大資料項的時間複雜度為O(1),但是插入還是需要較長的O(N)時間,這是因為必須移動陣列中平均一半的資料項以插入新資料項,並在完成插入後,陣列依然有序。

本文主要介紹實現優先順序佇列的另一種結構:堆。堆是一種樹,並非java和C++等編譯語言裡的“堆”。由它實現的優先順序佇列的插入和刪除的時間複雜度都是O(logN)。儘管這樣刪除的時間變慢了一些,但是插入的時間快的多了。當速度非常重要,且有很多插入操作是,可以選擇堆來實現優先順序佇列。堆有如下特點:

  • 它是完全二叉樹。即除了樹的最後一層節點不需要是滿的外,其他的每一層從左到右都完全是滿的。

  • 它常常用一個數組實現。用陣列實現的完全二叉樹中,節點的索引有如下特點(設該節點的索引為x):
    它的父節點的索引為 (x-1) / 2; 它的左子節點索引為 2x + 1; 它的右子節點索引為 2x + 2。

  • 堆中每個節點的關鍵字都大於(或等於)這個節點的子節點的關鍵字。這也是堆中每個節點必須滿足的條件。所以堆和二叉搜尋樹相比,是弱序的。

 

向堆中插入資料,首先將資料項存放到葉節點中(即存到陣列的最後一項),然後從該節點開始,逐級向上調整,直到滿足堆中節點關鍵字的條件為止。

從堆中刪除資料與插入不同,刪除時永遠刪除根節點的資料,因為根節點的資料最大,刪除完後,將最後一個葉節點移到根的位置,然後從根開始,逐級向下調整,直到滿足堆中節點關鍵字的條件為止。

原理就這麼多,堆真的很簡單

下面給出堆的實現程式碼:

package com.jt.ec.salesorder.web.controller;
public class Heap {
	private Node[] heapArray;
	private int maxSize;
	private int currentSize;
	public Heap(int mx) {
		maxSize = mx;
		currentSize = 0;
		heapArray = new Node[maxSize];
	}

	public boolean isEmpty() {
		return (currentSize == 0) ? true : false;
	}

	public boolean isFull() {
		return (currentSize == maxSize) ? true : false;
	}

	public boolean insert(int key) {
		if (isFull()) {
			return false;
		}
		Node newNode = new Node(key);
		heapArray[currentSize] = newNode;
		trickleUp(currentSize++);
		return true;
	}

	// 向上調整
	public void trickleUp(int index) {
		int parent = (index - 1) / 2;
		// 父節點的索引
		Node bottom = heapArray[index];
		// 將新加的尾節點存在bottom中
		while (index > 0 && heapArray[parent].getKey() < bottom.getKey()) {
			heapArray[index] = heapArray[parent];
			index = parent;
			parent = (parent - 1) / 2;
		}
		heapArray[index] = bottom;
	}

	public Node remove() {
		Node root = heapArray[0];
		heapArray[0] = heapArray[--currentSize];
		trickleDown(0);
		return root;
	}

	// 向下調整
	public void trickleDown(int index) {
		Node top = heapArray[index];
		int largeChildIndex;
		while (index < currentSize / 2) {
			// while node has at least one child
			int leftChildIndex = 2 * index + 1;
			int rightChildIndex = leftChildIndex + 1;
			// find larger child
			if (rightChildIndex < currentSize  // rightChild exists?
					&& heapArray[leftChildIndex].getKey() < heapArray[rightChildIndex].getKey()) {
				largeChildIndex = rightChildIndex;
			} else {
				largeChildIndex = leftChildIndex;
			}
			if (top.getKey() >= heapArray[largeChildIndex].getKey()) {
				break;
			}
			heapArray[index] = heapArray[largeChildIndex];
			index = largeChildIndex;
		}
		heapArray[index] = top;

	}

	// 根據索引改變堆中某個資料
	public boolean change(int index, int newValue) {
		if (index < 0 || index >= currentSize) {
			return false;
		}
		int oldValue = heapArray[index].getKey();
		heapArray[index].setKey(newValue);

		if (oldValue < newValue) {
			trickleUp(index);
		} else {
			trickleDown(index);
		}
		return true;
	}

	public void displayHeap() {
		System.out.println("heapArray(array format): ");
		for (int i = 0; i < currentSize; i++) {
			if (heapArray[i] != null) {
				System.out.print(heapArray[i].getKey() + " ");
			} else {
				System.out.print("--");
			}
		}
	}
}

class Node {
	private int iData;
	public Node(int key) {
		iData = key;
	}
	public int getKey() {
		return iData;
	}
	public void setKey(int key) {
		iData = key;
	}
}

引自:https://mp.weixin.qq.com/s/puq01hD6H9rHBr3mBXZpxw