最大堆與最小堆的實現

最近算法課作業是最小堆,於是便順便寫了這個代碼
最(大)小堆的性質:
(1)是一顆完全二叉樹,遵循完全二叉樹的所有性質。
(2)父節點的鍵值(大於)小於等於子節點的鍵值
(3)在堆排序中我們通常用的是最大堆,最小堆通常用在優先隊列中

代碼地址:https://github.com/whu-enjoy/Algorithms 倉庫的子文件夾heap中可以得到
https://github.com/whu-enjoy/Algorithms/tree/master/heap

/**************************************https://github.com/whu-enjoy/Algorithms/tree/master/heap****************************************
    程序員       : enjoy5512
    最後修改時間 : 2016年3月30日 17:09:08
    函數說明     : 這個代碼用來測試最大堆的插入刪除排序等用法
******************************************************************************/

#include<stdio.h>
#include<stdlib.h>
#include<math.h>

#define Size 11

/*
函數說明 :
    這個函數用於最大堆的上移操作
輸入參數 :
    heap : 需要移動的堆
    i    : 需要移動的數在堆中的位置(1-n)
輸出參數 :
    0
*/
int SiftUp(int heap[],int i)
{
    int temp = 0;

    //循環移動,i等於1則退出
    for (;1 != i;i = i / 2)
    {
        //子節點大於父節點則上移,否則退出
        if (heap[i - 1] > heap[(i - 2) / 2 ])
        {
            temp = heap[i - 1];
            heap[i - 1] = heap[(i -2) / 2];
            heap[(i -2) / 2] = temp;
        }
        else
        {
            break;
        }
    }

    return 0;
}

/*
函數說明 :
    這個函數用於最大堆的下移操作
輸入參數 :
    heap : 需要移動的堆
    i    : 需要移動的數在堆中的位置(1-n)
    n    : 堆的大小
輸出參數 :
    0
*/
int SiftDown(int heap[],int i,int n)
{
    int temp = 0;

    //循環移動,直到子節點大於堆的大小時退出
    for (;2*i <= n;)
    {
        i = i * 2;

        //尋找子節點中最大的子節點,作爲下移的對象
        if ((i + 1 <= n) && (heap[i] > heap[i - 1]))
        {
            i = i + 1;
        }

        //若父節點比子節點小則下移,否則結束
        if (heap[(i - 2) / 2] < heap[i - 1])
        {
            temp = heap[(i - 2) / 2];
            heap[(i - 2) / 2] = heap[i - 1];
            heap[i - 1] = temp;
        }
        else
        {
            break;
        }

    }

    return 0;
}

/*
函數說明 :
    這個函數用於最大堆的插入操作
輸入參數 :
    oldheap : 原來的堆
    n       : 原來的堆的大小
    newheap : 新的堆
    x       : 需要插入的數據
輸出參數 :
    0
*/
int Insert(int oldheap[],int n,int newheap[],int x)
{
    int i = 0;

    //循環將原來的堆複製到新的堆
    for(i = 0 ;i < n ;i++)
    {
        newheap[i] = oldheap[i];
    }
    newheap[n] = x;             //將插入的值插入到新的堆的最後一個
    SiftUp(newheap,n+1);        //上移操作

    return 0;
}

/*
函數說明 :
    這個函數用於最大堆的刪除操作
輸入參數 :
    oldheap : 原來的堆
    n       : 原來的堆的大小
    newheap : 新的堆
    i       : 需要刪除的數據在堆中的位置
輸出參數 :
    0
*/
int Delete(int oldheap[],int n,int newheap[],int i)
{
    int j = 0;
    int temp = 0;

    //循環將原來的堆的前n-1個數據複製到新的堆
    for (j = 0; j < n - 1; j++)
    {
        newheap[j] = oldheap[j];
    }
    temp = newheap[i - 1];            //保存堆要刪的元素
    newheap[i - 1] = oldheap[n - 1];  //將要刪除的數據與最後一個元素交換位置

    //如果刪除的數據比最後一個數據小,則上移,否則下移
    if (newheap[i - 1] > temp)        
    {
        SiftUp(newheap,i);
    }
    else
    {
        SiftDown(newheap,i,10);
    }
    oldheap[n - 1] = 0;                //將原來的堆最後一個元素置爲0

    return 0;
}

/*
函數說明 :
    這個函數用於最大堆的刪除最大值操作
輸入參數 :
    heap : 需要刪除元素的堆
    n    : 堆的大小
輸出參數 :
    x    : 堆的最大值
*/
int DeleteMax(int heap[],int n)
{
    int x = 0;

    x = heap[0];
    Delete(heap,n,heap,1);             //刪除第一個元素

    return x;
}

/*
函數說明 :
    這個函數用於最大堆的創建操作
輸入參數 :
    heap : 需要創建的堆
    n    : 堆的大小
輸出參數 :
    0
*/
int Makeheap(int heap[],int n)
{
    int i = 0;

    //遍歷所有節點的父節點,對每個遍歷的節點進行下移操作
    for(i = n/2;i > 0;i--)
    {
        SiftDown(heap,i,n);
    }

    return 0;
}

/*
函數說明 :
    這個函數用於最大堆的排序操作
輸入參數 :
    heap : 需要排序的堆
    n    : 堆的大小
輸出參數 :
    0
*/
int heapsort(int heap[],int n)
{
    int i = 0;
    int temp = 0;

    Makeheap(heap,n);             //先創建堆

    //每次取出最大的元素放到數組的最後面
    //然後每次對堆的第一個元素進行下移操作(範圍1-(i-1))
    for(i = n; i > 1; i--)
    {
        temp = heap[0];
        heap[0] = heap[i-1];
        heap[i-1] = temp;
        SiftDown(heap,1,i-1);
    }
}


/*
函數說明 :
    這個函數用於顯示堆,堆的最下層數據不得超過40,每個數據不得超過兩位數
    否則格式將出現問題
輸入參數 :
    heap : 需要顯示的堆
    n    : 堆的大小
輸出參數 :
    0
*/
int Showheap(int heap[],int n)
{
    int i = 0;
    int j = 0;
    int k = 0;
    int count = 0;
    int backspace = 0;
    int high = 0;

    high = log(n)/log(2) + 1;         //求出堆的高度

    for(k = 0; k < high - 1;k++)
    {
        count = pow(2,k);             //每行打印的數據數
        backspace = pow(2,high-k)-1;  //每行兩個數據之間的空格數

        for(j = 0;j < (backspace-1)/2;j++)
        {
            printf("  ");
        }
        for(i = 0; i < count; i++)
        {
            printf("%2d",heap[count+i-1]);
            for(j = 0;j < backspace;j++)
            {
                printf("  ");
            }
        }
        printf("\n");
    }
    i = pow(2,k) - 1;
    printf("%d",heap[i]);
    i++;
    for(; i < n; i++)     //打印最後一排數據
    {
        if(0 != heap[i])
        {
            printf("  %2d",heap[i]);
        }
    }
    printf("\n");

    return 0;
}

int main(void)
{
    int heap[Size] = {4,3,12,10,11,13,7,30,17,26,0};

    printf("數組原來的樣子:\n");
    Showheap(heap,Size - 1);

    printf("\n\n創建堆:\n");
    Makeheap(heap,Size - 1);
    Showheap(heap,Size - 1);

    printf("\n\n第九個位置上的數變成20:\n");
    heap[8] = 20;
    SiftUp(heap,9);
    Showheap(heap,Size - 1);

    printf("\n\n第二個位置上的數變成2:\n");
    heap[1] = 2;
    SiftDown(heap,2,Size-1);
    Showheap(heap,Size - 1);

    printf("\n\n插入一個元素15:\n");
    Insert(heap,Size - 1,heap,15);
    Showheap(heap,Size);

    printf("\n\n刪除第三個元素13:\n");
    Delete(heap,Size,heap,3);
    Showheap(heap,Size);

    printf("\n\n刪除最大值:\n");
    DeleteMax(heap,Size-1);
    Showheap(heap,Size-1);

    printf("\n\n堆排序:\n");
    heapsort(heap,Size-2);
    Showheap(heap,Size-2);

    system("pause");
    return 0;
}

最小堆跟最大堆實現方式差不多

/******************************************************************************
    程序員       : enjoy5512
    最後修改時間 : 2016年3月30日 20:36:18
    函數說明     : 這個代碼用來測試最小堆的插入刪除排序等用法
******************************************************************************/

#include<stdio.h>
#include<stdlib.h>
#include<math.h>

#define Size 11

/*
函數說明 :
    這個函數用於最小堆的上移操作
輸入參數 :
    heap : 需要移動的堆
    i    : 需要移動的數在堆中的位置(1-n)
輸出參數 :
    0
*/
int SiftUp(int heap[],int i)
{
    int temp = 0;

    //循環移動,i等於1則退出
    for (;1 != i;i = i / 2)
    {
        //子節點小於父節點則上移,否則退出
        if (heap[i - 1] < heap[(i - 2) / 2 ])
        {
            temp = heap[i - 1];
            heap[i - 1] = heap[(i -2) / 2];
            heap[(i -2) / 2] = temp;
        }
        else
        {
            break;
        }
    }

    return 0;
}

/*
函數說明 :
    這個函數用於最小堆的下移操作
輸入參數 :
    heap : 需要移動的堆
    i    : 需要移動的數在堆中的位置(1-n)
    n    : 堆的大小
輸出參數 :
    0
*/
int SiftDown(int heap[],int i,int n)
{
    int temp = 0;

    //循環移動,直到子節點序號大於堆的大小時退出
    for (;2*i <= n;)
    {
        i = i * 2;

        //尋找子節點中最小的子節點,作爲下移的對象
        if ((i + 1 <= n) && (heap[i] < heap[i - 1]))
        {
            i = i + 1;
        }

        //若父節點比子節點大則下移,否則結束
        if (heap[(i - 2) / 2] > heap[i - 1])
        {
            temp = heap[(i - 2) / 2];
            heap[(i - 2) / 2] = heap[i - 1];
            heap[i - 1] = temp;
        }
        else
        {
            break;
        }

    }

    return 0;
}

/*
函數說明 :
    這個函數用於最小堆的插入操作
輸入參數 :
    oldheap : 原來的堆
    n       : 原來的堆的大小
    newheap : 新的堆
    x       : 需要插入的數據
輸出參數 :
    0
*/
int Insert(int oldheap[],int n,int newheap[],int x)
{
    int i = 0;

    //循環將原來的堆複製到新的堆
    for(i = 0 ;i < n ;i++)
    {
        newheap[i] = oldheap[i];
    }
    newheap[n] = x;             //將插入的值插入到新的堆的最後一個
    SiftUp(newheap,n+1);        //上移操作

    return 0;
}

/*
函數說明 :
    這個函數用於最小堆的刪除操作
輸入參數 :
    oldheap : 原來的堆
    n       : 原來的堆的大小
    newheap : 新的堆
    i       : 需要刪除的數據在堆中的位置
輸出參數 :
    0
*/
int Delete(int oldheap[],int n,int newheap[],int i)
{
    int j = 0;
    int temp = 0;

    //循環將原來的堆的前n-1個數據複製到新的堆
    for (j = 0; j < n - 1; j++)
    {
        newheap[j] = oldheap[j];
    }
    temp = newheap[i - 1];            //保存堆要刪的元素
    newheap[i - 1] = oldheap[n - 1];  //將要刪除的數據與最後一個元素交換位置

    //如果刪除的數據比最後一個數據大,則上移,否則下移
    if (newheap[i - 1] < temp)        
    {
        SiftUp(newheap,i);
    }
    else
    {
        SiftDown(newheap,i,10);
    }
    oldheap[n - 1] = 4294967295;                //將原來的堆最後一個元素置爲0

    return 0;
}

/*
函數說明 :
    這個函數用於最小堆的刪除最大值操作
輸入參數 :
    heap : 需要刪除元素的堆
    n    : 堆的大小
輸出參數 :
    x    : 堆的最大值
*/
int DeleteMax(int heap[],int n)
{
    int x = 0;

    x = heap[0];
    Delete(heap,n,heap,1);             //刪除第一個元素

    return x;
}

/*
函數說明 :
    這個函數用於最小堆的創建操作
輸入參數 :
    heap : 需要創建的堆
    n    : 堆的大小
輸出參數 :
    0
*/
int Makeheap(int heap[],int n)
{
    int i = 0;

    //遍歷所有節點的父節點,對每個遍歷的節點進行下移操作
    for(i = n/2;i > 0;i--)
    {
        SiftDown(heap,i,n);
    }

    return 0;
}

/*
函數說明 :
    這個函數用於最小堆的排序操作
輸入參數 :
    heap : 需要排序的堆
    n    : 堆的大小
輸出參數 :
    0
*/
int heapsort(int heap[],int n)
{
    int i = 0;
    int temp = 0;

    Makeheap(heap,n);             //先創建堆

    //每次取出最小的元素放到數組的最後面
    //然後每次對堆的第一個元素進行下移操作(範圍1-(i-1))
    for(i = n; i > 1; i--)
    {
        temp = heap[0];
        heap[0] = heap[i-1];
        heap[i-1] = temp;
        SiftDown(heap,1,i-1);
    }
}


/*
函數說明 :
    這個函數用於顯示堆,堆的最下層數據不得超過40,每個數據不得超過兩位數
    否則格式將出現問題
輸入參數 :
    heap : 需要顯示的堆
    n    : 堆的大小
輸出參數 :
    0
*/
int Showheap(int heap[],int n)
{
    int i = 0;
    int j = 0;
    int k = 0;
    int count = 0;
    int backspace = 0;
    int high = 0;

    high = log(n)/log(2) + 1;         //求出堆的高度

    for(k = 0; k < high - 1;k++)
    {
        count = pow(2,k);             //每行打印的數據數
        backspace = pow(2,high-k)-1;  //每行兩個數據之間的空格數

        for(j = 0;j < (backspace-1)/2;j++)
        {
            printf("  ");
        }
        for(i = 0; i < count; i++)
        {
            printf("%2d",heap[count+i-1]);
            for(j = 0;j < backspace;j++)
            {
                printf("  ");
            }
        }
        printf("\n");
    }
    i = pow(2,k) - 1;
    printf("%d",heap[i]);
    i++;
    for(; i < n; i++)     //打印最後一排數據
    {
        if(4294967295 != heap[i])
        {
            printf("  %2d",heap[i]);
        }
    }
    printf("\n");

    return 0;
}

int main(void)
{
    int heap[Size] = {20,17,9,10,11,4,5,3,7,5,4294967295};

    printf("數組原來的樣子:\n");
    Showheap(heap,Size - 1);

    printf("\n\n創建堆:\n");
    Makeheap(heap,Size - 1);
    Showheap(heap,Size - 1);

    printf("\n\n第九個位置上的數變成6:\n");
    heap[8] = 6;
    SiftUp(heap,9);
    Showheap(heap,Size - 1);

    printf("\n\n第二個位置上的數變成19:\n");
    heap[1] = 19;
    SiftDown(heap,2,Size-1);
    Showheap(heap,Size - 1);

    printf("\n\n插入一個元素4:\n");
    Insert(heap,Size - 1,heap,4);
    Showheap(heap,Size);

    printf("\n\n刪除第三個元素4:\n");
    Delete(heap,Size,heap,3);
    Showheap(heap,Size);

    printf("\n\n刪除最小值:\n");
    DeleteMax(heap,Size-1);
    Showheap(heap,Size-1);

    printf("\n\n堆排序:\n");
    heapsort(heap,Size-1);
    Showheap(heap,Size-1);

    system("pause");
    return 0;
}
發佈了42 篇原創文章 · 獲贊 37 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章