基本數據結構 —— 堆以及堆排序(C++實現)


什么是堆

堆(英語:heap)是計算機科學中一類特殊的數據結構的統稱。堆通常是一個可以被看做一棵樹的數組對象。堆總是滿足下列性質:

  • 堆中某個節點的值總是不大於或不小於其父節點的值;
  • 堆總是一棵完全二叉樹。

通常將根節點最大的堆叫做最大堆或大根堆,根節點最小的堆叫做最小堆或小根堆。

堆的存儲

堆一般使用數組存儲。當堆中有n個元素的時,可以將這些元素存放在數組array的前n個單元里,其中堆的根節點中元素存放在array[1]中。結點之間的關系有兩種情況:

  • 如果根節點在數組中的位置是1,那么第i個位置的左右節點下標分別為2i、2i+1,父節點下標為i/2。
  • 如果根節點在數組中的位置是0,那么第i個位置的左右節點下標分別為2i+1、2i+2,父節點下標為⌊(i-1) /2⌋。

堆的操作

以大根堆為例,給出堆支持的一些操作。

結構體定義

struct Heap
{
    int size;   // number of elements in array
    int *array;
    Heap()  //init
    {
        size = 0;
        array = new int[maxn];
    }
    Heap(int n) //init
	{
		size = 0;
		array = new int[n];
	} 
	~Heap() //free memory
	{
		delete array;
	}
};

判斷是否為空

    bool empty()
    {
    	if(size != 0) return false;
    	return true;
    } 

往堆中插入元素

    void insert(int value) 
    {
        array[++size] = value; // 數組的最末尾插入新節點
        int index = size;
        while(index > 1)    // 自下而上地調整子節點與父節點的位置
        {
            // 如果大於父節點的值,根據最大堆的特點,子節點上升,而父節點要下降
        	if(array[index] > array[index/2]) swap(array[index],array[index/2]);  
    		index /= 2; // 繼續向上搜索
    	}
    }

從堆中刪除元素

    void del() 
	{
		if(empty()) return; // 刪除前不能為空
		swap(array[1],array[size--]); //用數組最末尾節點覆蓋被刪節點
		int index = 1;
		while(2*index <= size) // 從上到下調整二叉堆
		{
			int next = 2*index;
			// 選取子節點中最大的
			if(next < size && array[next+1] > array[next]) next++;
			// 與子節點中最大的比較,如果小於則當前結點下降
			if(array[index] < array[next]) 
			{
				swap(array[index],array[next]);
				index = next;
			} 
			else break;
		}
	}

取出堆中最大的元素

    int max() {
		if(empty()) return -1;
		return array[1];
	}

堆排序

給定一個有size個元素的數組array,可用下面的算法buildHeap(array,size)O(n) 時間內將數組array調整為一個堆。

void buildHeap(int array[],int size)
{
	int i,tmp,index;
	for(i = size/2; i >= 1; i--) 
	{
		tmp = array[i];
		index = 2*i;
		while(index <= size)
		{
			if(index < size && array[index+1] > array[index]) index++;
			if(array[index] < tmp) break;
			array[index/2]  = array[index];
			index *= 2;
		}
		array[index/2] = tmp;
	}
}

測試代碼

#include<iostream>
#include<algorithm>
#define maxn 1001   //heap's size

using namespace std;

struct Heap {
	int size;	// number of elements in array
	int *array;
	Heap() {	//init
		size = 0;
		array = new int[maxn];
	}
	Heap(int n) {	//init
		size = 0;
		array = new int[n];
	}
	~Heap() {	//free memory
		delete array;
	}
	bool empty() {
		if(size != 0) return false;
		return true;
	}
	void insert(int value) {
		array[++size] = value;
		int index = size;
		while(index > 1) {
			if(array[index] > array[index/2]) swap(array[index],array[index/2]);
			index /= 2;
		}
	}
	void del() 
	{
		if(empty()) return;
		swap(array[1],array[size--]);
		int index = 1;
		while(2*index <= size) 
		{
			int next = 2*index;
			if(next < size && array[next+1] > array[next]) next++;
			if(array[index] < array[next]) 
			{
				swap(array[index],array[next]);
				index = next;
			} else break;
		}
	}
	int max() {
		if(empty()) return -1;
		return array[1];
	}
};
void buildHeap(int array[],int size) {
	int i,tmp,index;
	for(i = size/2; i >= 1; i--) {
		tmp = array[i];
		index = 2*i;
		while(index <= size) {
			if(index < size && array[index+1] > array[index]) index++;
			if(array[index] < tmp) break;
			array[index/2]  = array[index];
			index *= 2;
		}
		array[index/2] = tmp;
	}
}
int main() {
	int n,i,j,k;
	cout << "input heap's size:";
	cin >> n;
	Heap H = Heap(n);
	int* array = new int[n];
	for(i = 1; i <= n; i++) {
		int tmp;
		cin >> tmp;
		array[i] = tmp;
		H.insert(tmp);
	}
	buildHeap(array,n);
	for(i = 1; i <= n; i++) {
		cout << array[i] << " ";
	}
	cout << endl;
	while(!H.empty()) {
		cout << H.max() << endl;
		H.del();
	}
	return 0;
};

結果:

例題

最小的K個數 —— 劍指offer

輸入n個整數,找出其中最小的K個數。例如輸入4,5,1,6,2,7,3,8這8個數字,則最小的4個數字是1,2,3,4。

class Solution {
public:
    struct Heap {
        int size;	// number of elements in array
        int *array;
        Heap() {	//init
            size = 0;
            array = new int[1001];
        }
        Heap(int n) {	//init
            size = 0;
            array = new int[n];
        }
        ~Heap() {	//free memory
            delete array;
        }
        bool empty() {
            if(size != 0) return false;
            return true;
        }
        void insert(int value) {
            array[++size] = value;
            int index = size;
            while(index > 1) {
                if(array[index] < array[index/2]) swap(array[index],array[index/2]);
                index /= 2;
            }
        }
        void del() 
        {
            if(empty()) return;
            swap(array[1],array[size--]);
            int index = 1;
            while(2*index <= size) 
            {
                int next = 2*index;
                if(next < size && array[next+1] < array[next]) next++;
                if(array[index] > array[next]) 
                {
                    swap(array[index],array[next]);
                    index = next;
                } else break;
            }
        }
        int min() {
            if(empty()) return -1;
            return array[1];
        }
    };
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> ret;
        int i,n = input.size();
        if(n < k) return ret;
        Heap H = Heap(n);
        for(i = 0;i < n;i++)
        {
            H.insert(input[i]);
        }
        while(k) 
        {
            ret.push_back(H.min());
            H.del();
            k--;
	    }
        return ret;
    }
};

參考資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM