數據結構-堆 C與C++的實現


堆,是一種完全二叉樹。而且在這顆樹中,父節點必然大於(對於小頂堆為小於)子節點。

關於樹的概念不了解可以看這里:http://www.cnblogs.com/HongYi-Liang/p/7231440.html

由於堆是一種完全二叉樹,很適合保存為數組的形式。如下圖示意的堆,紅色數字為數組索引,黑色數字為數組的值,那么這個堆保存為數組的形式:heap={9,8,5,6,7,1,4,0,3,2};

值得注意的是,在堆中,若設父親的索引為i,左兒子的索引剛好等於2i,而右兒子的索引等於2i+1。這個公式會大量地出現在下邊的程序中。

關鍵概念:

大頂堆:樹根元素為最大值往葉子遞減,(父節點總是大於子節點)

小頂堆:樹根元素為最小值往葉子遞增,(父節點總是小於子節點)

 

下為一個大頂堆的示意圖,父節點總是大於子節點

 

 

在下面的程序中,C將以大頂堆的形式編寫,C++以小頂堆的形式編寫。


 

C語言

程序源碼:

本例子為大頂堆,包含4個文件(如下圖)

MaxHeap.c

#include "MaxHeap.h"

bool MaxHeapConstructByBuffer(MaxHeap *heap,MAXHEAP_ELEM buff[],int length);
bool MaxHeapDesturct(MaxHeap *heap);
bool MaxHeap_getSize(MaxHeap *heap);
bool MaxHeap_isFull(MaxHeap *heap);
bool MaxHeap_isEmpty(MaxHeap *heap);
void MaxHeap_swap(MAXHEAP_ELEM *a,MAXHEAP_ELEM *b);
void MaxHeap_floating(MaxHeap *heap,int index);
void MaxHeap_sink(MaxHeap *heap, int index);
bool MaxHeap_push(MaxHeap *heap,MAXHEAP_ELEM data);
bool MaxHeap_push(MaxHeap *heap,MAXHEAP_ELEM data);
bool MaxHeap_pop(MaxHeap *heap,int index);
void MaxHeap_printfAll(MaxHeap *heap);

bool MaxHeapConstructByBuffer(MaxHeap *heap,MAXHEAP_ELEM buff[],int length)
{
    int i;
    if(NULL != heap->iDatas)
    {
        return false;
    }
    heap->iHeapCapacity=length;
    heap->iHeapSize=0;
    heap->iDatas = (MAXHEAP_ELEM*)malloc(sizeof(MAXHEAP_ELEM)*length);
    for(i=0;i<length;i++)
    {
        MaxHeap_push(heap,buff[i]);
    }
    return true;
}

bool MaxHeapDesturct(MaxHeap *heap)
{
    if(NULL == heap->iDatas)
    {
        return false;
    }
    free(heap->iDatas);
    return true;
}

bool MaxHeap_getSize(MaxHeap *heap)
{
    return heap->iHeapSize;
}

bool MaxHeap_isFull(MaxHeap *heap)
{
    if(heap->iHeapCapacity == heap->iHeapSize)
    {
        return true;
    }
    return false;
}

bool MaxHeap_isEmpty(MaxHeap *heap)
{
    if(0 == heap->iHeapSize)
    {
        return true;
    }
    return false;
}

void MaxHeap_swap(MAXHEAP_ELEM *a,MAXHEAP_ELEM *b)
{
    MAXHEAP_ELEM temp;
    temp=*a;
    *a=*b;
    *b=temp;
}

void MaxHeap_floating(MaxHeap *heap,int index)
{
    int i;
    for(i=index;i>0;i=(int)(i*0.5))
    {
        if(heap->iDatas[i-1] > heap->iDatas[(int)(i*0.5-1)] )
        {
            MaxHeap_swap(&heap->iDatas[i-1],&heap->iDatas[(int)(i*0.5-1)]);
        }
        else 
        {
            break;
        }
    }    
}


void MaxHeap_sink(MaxHeap *heap, int index)
{
    int i=index;

    while(i*2<=heap->iHeapSize)
    {
        if(heap->iDatas[i-1] < heap->iDatas[i*2-1])//it compare to left child
        {
            MaxHeap_swap(&heap->iDatas[i-1],&heap->iDatas[i*2-1]);
            if(i*2+1<=heap->iHeapSize && heap->iDatas[i-1] < heap->iDatas[i*2])//it compare to right child
            {
                MaxHeap_swap(&heap->iDatas[i-1],&heap->iDatas[i*2]);            
            }
            /*index*/
            i=i*2;
        }
        else if(i*2+1<=heap->iHeapSize && heap->iDatas[i-1] < heap->iDatas[i*2])//it compare to right child
        {
            MaxHeap_swap(&heap->iDatas[i-1],&heap->iDatas[i*2]);
            i=i*2+1;
        }
        else
        {
            break;
        }
    }    
}

bool MaxHeap_push(MaxHeap *heap,MAXHEAP_ELEM data)
{
    if( MaxHeap_isFull(heap))
        return false;
    heap->iDatas[heap->iHeapSize]=data;
    heap->iHeapSize++;
    MaxHeap_floating(heap,heap->iHeapSize);

    return true;
}

bool MaxHeap_pop(MaxHeap *heap,int index)
{
    if(MaxHeap_isEmpty(heap))
        return false;
    heap->iDatas[index]=heap->iDatas[heap->iHeapSize-1];
    heap->iHeapSize--;
    MaxHeap_sink(heap,index+1);

    return true;
}

void MaxHeap_printfAll(MaxHeap *heap)
{
    int i;
    printf("heap:");
    for( i=0;i<heap->iHeapSize;i++)
    {
        printf("%d ",heap->iDatas[i]);
    }
    printf("\r\n");
}
View Code

MaxHeap.h

#ifndef __MAXHEAP_H
#define __MAXHEAP_H

#include <stdlib.h>
#include <stdio.h>
#include "Mystdbool.h"

typedef int MAXHEAP_ELEM;
typedef struct 
{
    int iHeapCapacity;
    int iHeapSize;
    MAXHEAP_ELEM *iDatas;
}MaxHeap;

bool MaxHeapConstructByBuffer(MaxHeap *heap,MAXHEAP_ELEM buff[],int length);
bool MaxHeapDesturct(MaxHeap *heap);
bool MaxHeap_getSize(MaxHeap *heap);
bool MaxHeap_isFull(MaxHeap *heap);
bool MaxHeap_isEmpty(MaxHeap *heap);
void MaxHeap_swap(MAXHEAP_ELEM *a,MAXHEAP_ELEM *b);
void MaxHeap_floating(MaxHeap *heap,int index);
void MaxHeap_sink(MaxHeap *heap, int index);
bool MaxHeap_push(MaxHeap *heap,MAXHEAP_ELEM data);
bool MaxHeap_push(MaxHeap *heap,MAXHEAP_ELEM data);
bool MaxHeap_pop(MaxHeap *heap,int index);
void MaxHeap_printfAll(MaxHeap *heap);

#endif
View Code

Mystdbool.h(僅用於聲明布爾類)

#ifndef _MYSTDBOOL_H
#define _MYSTDBOOL_H

typedef enum Bool
{
    false=0,
    true,
}bool;




#endif
View Code

main.c

#include "MaxHeap.h"



int main()
{
    /*int buffer[10]={9,8,7,6,5,4,3,2,1,0};*/
    int buffer[10]={0,1,2,3,4,5,6,7,8,9};
    MaxHeap heap={0};
    MaxHeapConstructByBuffer(&heap,buffer,10);
    MaxHeap_printfAll(&heap);
    MaxHeap_pop(&heap,0);
    MaxHeap_printfAll(&heap);
    MaxHeap_pop(&heap,0);
    MaxHeap_printfAll(&heap);
    system("pause");
    return 0;
}
View Code

運行結果:

源碼詳解:

上浮:floating(int index) 

 

  1. 將堆第index個元素與它的父親比較,若小於它的父親,則與它父親交換數值。
  2. 上述過程如果發生,則把它繼續上浮。
void MaxHeap_floating(MaxHeap *heap,int index)
{
    int i;
    for(i=index;i>0;i=(int)(i*0.5))
    {
        if(heap->iDatas[i-1] > heap->iDatas[(int)(i*0.5-1)] )
        {
            MaxHeap_swap(&heap->iDatas[i-1],&heap->iDatas[(int)(i*0.5-1)]);
        }
        else 
        {
            break;
        }
    }    
}

 

添加元素:push(T data)

  1. 把元素添加到堆的最后。
  2. 並使用上浮方法把堆的最后一個元素上浮。
bool MaxHeap_push(MaxHeap *heap,MAXHEAP_ELEM data)
{
    if( MaxHeap_isFull(heap))
        return false;
    heap->iDatas[heap->iHeapSize]=data;
    heap->iHeapSize++;
    MaxHeap_floating(heap,heap->iHeapSize);

    return true;
}

 

構建堆:MaxHeapConstructByBuffer()

  1. 用malloc為數據申請空間。
  2. 一個一個地將buff中的數據push()到堆中。
bool MaxHeapConstructByBuffer(MaxHeap *heap,MAXHEAP_ELEM buff[],int length)
{
    int i; if(NULL != heap->iDatas) { return false; } heap->iHeapCapacity=length; heap->iHeapSize=0; heap->iDatas = (MAXHEAP_ELEM*)malloc(sizeof(MAXHEAP_ELEM)*length); for(i=0;i<length;i++) { MaxHeap_push(heap,buff[i]); } return true; }

下沉:

  1. 從根開始,用父節點與左子節點比較。若父節點大於左子,則交換它們的值
  2. 用父節點與右子節點比較。若父節點大於右子,則交換它們的值。
  3. 若上述情況發生了,則繼續下沉,直到無法下沉為止。
void MaxHeap_sink(MaxHeap *heap, int index)
{
    int i=index;

    while(i*2<=heap->iHeapSize)
    {
        if(heap->iDatas[i-1] < heap->iDatas[i*2-1])//it compare to left child
        {
            MaxHeap_swap(&heap->iDatas[i-1],&heap->iDatas[i*2-1]);
            if(i*2+1<=heap->iHeapSize && heap->iDatas[i-1] < heap->iDatas[i*2])//it compare to right child
            {
                MaxHeap_swap(&heap->iDatas[i-1],&heap->iDatas[i*2]);            
            }
            /*index*/
            i=i*2;
        }
        else if(i*2+1<=heap->iHeapSize && heap->iDatas[i-1] < heap->iDatas[i*2])//it compare to right child
        {
            MaxHeap_swap(&heap->iDatas[i-1],&heap->iDatas[i*2]);
            i=i*2+1;
        }
        else
        {
            break;
        }
    }    
}

刪除元素:pop(int index)

  1. 把堆的第index個元素刪除,並把堆的最后一個元素放到index處。
  2. 把堆的第index個元素下沉
bool MaxHeap_pop(MaxHeap *heap,int index)
{
    if(MaxHeap_isEmpty(heap))
        return false;
    heap->iDatas[index]=heap->iDatas[heap->iHeapSize-1];
    heap->iHeapSize--;
    MaxHeap_sink(heap,index+1);

    return true;
}

 


 

C++

程序源碼:

本例子為小頂堆,包含2個文件(如下圖)

MyMinHeap.h:

此文件中為小頂堆的類模板。

#ifndef __MYMINHEAP_H
#define __MYMINHEAP_H
#include <iostream>
#include <vector>


using namespace std;


template <typename T>
class MyMinHeap
{
public:
    MyMinHeap(T buff[],int length);
    MyMinHeap(int capacity);
    virtual ~MyMinHeap();
    int getSize();
    bool isFull();
    bool isEmpty();
    void swap(vector<T> &vec,int i,int j);
    void floating(int index);
    void sink(int index);
    bool push(T data);
    bool pop(int index);
    //transval
    void printfAll();
private:
    int m_iHeapCapacity;
    int m_iHeapSize;
    vector<T> m_vecData;
};


template <typename T>
MyMinHeap<T>::MyMinHeap(T buff[],int length)
{
    m_iHeapCapacity=length;
    m_iHeapSize=0;
    m_vecData.resize(length);
    for(int i=0;i<length;i++)
    {
        push(buff[i]);
    }
}

template <typename T>
MyMinHeap<T>::    MyMinHeap(int capacity)
{
    m_iHeapCapacity=capacity;
    m_iHeapSize=0;
    m_vecData.resize(capacity);
}

template <typename T>
MyMinHeap<T>::~MyMinHeap()
{

}

template <typename T>
int MyMinHeap<T>::getSize()
{
    return m_iHeapSize;
}

template <typename T>
bool MyMinHeap<T>::isFull()
{
    if(m_iHeapSize>=m_iHeapCapacity)
    {
        return true;
    }
    return false;
}
template <typename T>
bool MyMinHeap<T>::isEmpty()
{
    if(m_iHeapSize==0)
        return true;
    return false;
}

template <typename T>
void MyMinHeap<T>::swap(vector<T> &vec,int i,int j)
{
    T temp = vec[i];
    vec[i]=vec[j];
    vec[j]=temp;
}

template <typename T>
void MyMinHeap<T>::floating(int index)
{
    T temp;
    for(int i=index;i>0;i*=0.5)
    {
        if(m_vecData[i-1]<m_vecData[i*0.5-1] )
        {
            swap(m_vecData,i-1,i*0.5-1);
        }
        else 
        {
            break;
        }
    }    
}


template <typename T>
void MyMinHeap<T>::sink(int index)
{
    int i=index;

    while(i*2<=m_iHeapSize)
    {
        if(m_vecData[i-1]>m_vecData[i*2-1])//it compare to left child
        {
            swap(m_vecData,i-1,i*2-1);
            if(i*2+1<=m_iHeapSize && m_vecData[i-1]>m_vecData[i*2])//it compare to right child
            {
                swap(m_vecData,i-1,i*2);            
            }
            /*index*/
            i=i*2;
        }
        else if(i*2+1<=m_iHeapSize && m_vecData[i-1]>m_vecData[i*2])//it compare to right child
        {
            swap(m_vecData,i-1,i*2);
            i=i*2+1;
        }
        else
        {
            break;
        }
    }
}

template <typename T>
bool MyMinHeap<T>::push(T data)
{
    if(isFull())
        return false;
    m_vecData[m_iHeapSize]=data;
    m_iHeapSize++;
    floating(m_iHeapSize);

    return true;
}

template <typename T>
bool MyMinHeap<T>::pop(int index)
{
    if(isEmpty())
        return false;
    m_vecData[index]=m_vecData[m_iHeapSize-1];
    m_iHeapSize--;
    sink(index+1);

    return true;
}

template <typename T>
void MyMinHeap<T>::printfAll()
{
    cout<<"heap:";
    for(int i=0;i<m_iHeapSize;i++)
    {
        cout<<m_vecData[i]<<" ";
    }
    cout<<endl<<endl;
}


#endif
View Code

 

main.h:

主程序用於測試運行。

#include <iostream>
#include "MyMinHeap.h"
using namespace std;


int main()
{
    int buffer[10]={9,8,7,6,5,4,3,2,1,0};
    MyMinHeap<int> heap(buffer,10);
    heap.printfAll();
    heap.pop(1);
    heap.printfAll();
    heap.push(1);
    heap.printfAll();
    system("pause");
    return 0;
}
View Code

 

運行結果:

 

 

源碼詳解:

上浮:floating(int index)

  1. 將堆第index個元素與它的父親比較,若小於它的父親,則與它父親交換數值。
  2. 上述過程如果發生,則把它繼續上浮。
template <typename T>
void MyMinHeap<T>::floating(int index)
{
    T temp;
    for(int i=index;i>0;i*=0.5)
    {
        if(m_vecData[i-1]<m_vecData[i*0.5-1] )
        {
            swap(m_vecData,i-1,i*0.5-1);
        }
        else 
        {
            break;
        }
    }    
}

 

添加元素:push(T data)

  1. 把元素添加到堆的最后。
  2. 並使用上浮方法把堆的最后一個元素上浮。
template <typename T>
bool MyMinHeap<T>::push(T data)
{
    if(isFull())
        return false;
    m_vecData[m_iHeapSize]=data;
    m_iHeapSize++;
    floating(m_iHeapSize);

    return true;
}

 

構造函數:使用數組構建堆:

連續使用push()把buff中所有元素一個一個地加入堆中。

template <typename T>
MyMinHeap<T>::MyMinHeap(T buff[],int length)
{
    m_iHeapCapacity=length;
    m_iHeapSize=0;
    m_vecData.resize(length);
    for(int i=0;i<length;i++)
    {
        push(buff[i]);
    }
}

 

下沉:

  1. 從根開始,用父節點與左子節點比較。若父節點大於左子,則交換它們的值
  2. 用父節點與右子節點比較。若父節點大於右子,則交換它們的值。
  3. 若上述情況發生了,則繼續下沉,直到無法下沉為止。
template <typename T>
void MyMinHeap<T>::sink(int index)
{
    int i=index;

    while(i*2<=m_iHeapSize)
    {
        if(m_vecData[i-1]>m_vecData[i*2-1])//it compare to left child
        {
            swap(m_vecData,i-1,i*2-1);
            if(i*2+1<=m_iHeapSize && m_vecData[i-1]>m_vecData[i*2])//it compare to right child
            {
                swap(m_vecData,i-1,i*2);            
            }
            /*index*/
            i=i*2;
        }
        else if(i*2+1<=m_iHeapSize && m_vecData[i-1]>m_vecData[i*2])//it compare to right child
        {
            swap(m_vecData,i-1,i*2);
            i=i*2+1;
        }
        else
        {
            break;
        }
    }
}

 

刪除元素:pop(int index)

  1. 把堆的第index個元素刪除,並把堆的最后一個元素放到index處。
  2. 把堆的第index個元素下沉
template <typename T>
bool MyMinHeap<T>::pop(int index)
{
    if(isEmpty())
        return false;
    m_vecData[index]=m_vecData[m_iHeapSize-1];
    m_iHeapSize--;
    sink(index+1);

    return true;
}

 


 

 

 


免責聲明!

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



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