<acronym id="xonnx"></acronym>
      <td id="xonnx"></td>
    1. <pre id="xonnx"></pre>

      1. 專注電子技術學習與研究
        當前位置:單片機教程網 >> MCU設計實例 >> 瀏覽文章

        二叉堆的C語言實現

        作者:龔平   來源:本站原創   點擊數:  更新時間:2014年03月14日   【字體:

        二叉堆的實現數據結構中如何使用,我任務主要是在操作系統中的任務優先級調度問題,當然也可以用于實現堆排序問題,比如找出數組中的第K個最小值問題,采用二叉堆能夠快速的實現,今天我就采用C語言實現了一個簡單的二叉堆操作,完成這些數據結構我并不知道能干什么,我就當自己在練習C語言的功底吧。逐步完成自己的代碼,希望自己在知識的理解力上有一定的提高。
         
        二叉堆是非常有特點的數據結構,可以采用簡單的數組就能實現,當然鏈表的實現也是沒有問題的,畢竟是一個二叉樹問題,當然可以采用鏈表實現。采用數組實現時,可以找到兩個特別明顯的規律:
         
        左兒子:L_Son = Parent * 2;
        右兒子:R_Son = Parent * 2 + 1;
         
        二叉堆是一顆完全填滿的樹,可能例外的是在底層,底層上的元素是從左到右填入,當然二叉堆可以是基于大值的排序,也可以是基于小值的排列形式,本文采用簡單的基于小值的形式。主要完成的操作:1、最小值的刪除操作,該操作會刪除根節點,然后提升兒子節點來代替根節點,具體的實現過程中通過提升左右兒子中較小的作為父結點,依此提升直到到達最底層,這種實現方式叫做下慮法。2、數據的插入操作,插入操作可能會破壞二叉堆的結構,一般在最底層創建一個空穴,然后比較插入值與空穴父結點的值,如果大于父結點的值,那么直接插入到空穴中,如果小于父結點,則將父結點的值插入到剛創建的空穴中,在父結點所在位置上形成新的父結點,這時候再和父結點的父結點比較,具體操作如上所述,直到找到具體的插入地址。當結點個數為偶數時,在刪除操作中需要注意節點是否有右兒子的情況。具體的可以參考代碼中的說明。
         
        具體的實現如下:
        結構體:

         

            #ifndef __BINARYHEAP_H_H_
            #define __BINARYHEAP_H_H_

            #include <stdlib.h>
            #include <assert.h>

            #define bool int
            #define true 1
            #define false 0

            /*打算采用數組的方式實現完全二叉堆*/
            typedef struct _binaryheap
            {
                    /*因為需要動態擴展,
                    *采用靜態數組不方便*/
                    int * parray;
                    /*目前存在的結點*/
                    int currentSize;
                    /*樹的實際容量*/
                    int capacity;
            }BinaryHeap_t, *BinaryHeap_handle_t;

            #ifdef __cplusplus
            extern "C"
            {
            #endif

            bool init_BinaryHeap(BinaryHeap_handle_t heap, int capacity);
            bool alloc_BinaryHeap(BinaryHeap_handle_t *heap, int capacity);
            void delete_BinaryHeap(BinaryHeap_handle_t heap);
            void free_BinaryHeap(BinaryHeap_handle_t *heap);

            bool insert(BinaryHeap_handle_t heap,int value);
            int deleteMin(BinaryHeap_handle_t heap);
            bool isEmpty(BinaryHeap_handle_t heap);

            #ifdef __cplusplus
            }
            #endif

            #endif

        實現的接口函數如下:

         

            #include "binaryheap.h"

            bool isEmpty(BinaryHeap_handle_t heap)
            {
                    assert(heap != NULL);
                    return heap->currentSize == 0;
            }

            bool init_BinaryHeap(BinaryHeap_handle_t heap, int capacity)
            {
                    int *parray = NULL;

                    if(heap == NULL)
                            return false;
               
                    parray = (int *)calloc(capacity+1,sizeof(int));
                    if(parray == NULL)
                            return false;
               
                    heap->parray = parray;
                    heap->capacity = capacity;
                    heap->currentSize = 0;

                    return true;
            }

            void delete_BinaryHeap(BinaryHeap_handle_t heap)
            {
                    assert(heap != NULL && heap->parray != NULL);

                    heap->capacity = 0;
                    heap->currentSize = 0;

                    free(heap->parray);
                    heap->parray = NULL;
            }

            void free_BinaryHeap(BinaryHeap_handle_t *heap)
            {
                    assert(*heap != NULL);

                    (*heap)->capacity = 0;
                    (*heap)->currentSize = 0;

                    free((*heap)->parray);
                    (*heap)->parray = NULL;

                    free(*heap);
                    *heap = NULL;
            }

            bool alloc_BinaryHeap(BinaryHeap_handle_t *heap, int capacity)
            {
                    int *parray = NULL;

                    if(*heap != NULL)
                            return false;

                    *heap = (int *)calloc(1, sizeof(BinaryHeap_t));
                    if(*heap == NULL)
                            return false;

                    /*其中的1,主要是為了使得數組從下標1開始計算*/
                    parray =(int *)calloc(capacity + 1, sizeof(int));
                    if(parray == NULL)
                            return false;

                    (*heap)->parray = parray;
                    (*heap)->capacity = capacity;
                    (*heap)->currentSize = 0;

                    return true;
            }

            /**************************************************
             * 采用上慮法實現數據的插入操作
             * 上慮法的實現方式比較簡單,首先創建一個空節點
             * 然后將需要插入的值與當前空穴的父結點進行比較
             * 如果大于父結點,直接插入空穴中
             * 如果小于父結點的值,則將父結點的值下拉到空穴中
             * 之前父結點的位置就是空穴,接著與上層比較
             * 直到找到父結點大于當前插入值的情況
             **************************************************/
            bool insert(BinaryHeap_handle_t heap, int value)
            {
                    int index = 0;

                    if(heap == NULL || heap->parray == NULL)
                            return false;

                    /*得到一個新的空穴下標*/
                    index = ++heap->currentSize;
                    /*條件是不是第一個下標和插入值比對應父結點小*/
                    while(index > 1 && value < heap->parray[index/2])
                    {
                            /*將父結點保存到當前結點處*/
                            heap->parray[index] = heap->parray[index/2];
                            /*得到父結點的空穴位置*/
                            index /= 2;
                    }
                    /*將插入的值保存到剩余的空穴中*/
                    heap->parray[index] = value;

                    return true;
            }

            /***********************************************************
             * 下慮法實現數據的重排序操作
             * 實現的方式,將子結點的兩個兒子進行比較,將小的提升
             * 需要注意的是如何讓判斷節點是否一定存在右兒子
             * 實現的方式主要是利用了二叉堆的特性:
             * 2*pare = L_child
             * 2*pare + 1 = R_child;
             ***********************************************************/
            static void presort_BinaryHeap(BinaryHeap_handle_t heap,int hole)
            {
                    /*這是二叉堆的特性*/
                    int child = hole * 2;
                    /*保存當前數據操作*/
                    int tmp = 0;

                    assert(heap != NULL && heap->parray != NULL);

                    tmp = heap->parray[hole];
                    /*hold * 2 <= heap->currentSize 判斷了當前結點是否為最低層*/
                    for(; hole * 2 <= heap->currentSize; hole = child)
                    {
                            child = hole * 2;

                            /*******************************
                            *這句代碼解決是否存在右結點的問題
                            *并確定了那個子結點提升的問題
                            *******************************/
                            if((child != heap->currentSize)
                                    && (heap->parray[child + 1] < heap->parray[child]))
                                    child ++;

                            if(heap->parray[child] < tmp)
                            {
                                    /*將子結點提升為父結點*/
                                   heap->parray[hole] = heap->parray[child];
                            }
                    }
                    /*到達了最低的層,也就是樹葉*/
                    heap->parray[hole] = tmp;
            }

            /*實現數據的下慮法實現數據的刪除操作*/
            int deleteMin(BinaryHeap_handle_t heap)
            {
                    int ret = 0;
                    int index = 0;

                    assert(!isEmpty(heap));
                    /*需要返回的值*/
                    ret = heap->parray[1];

                    /*將最后需要釋放內存空間的值保存到第一個內存空間中*/
                    heap->parray[1] = heap->parray[heap->currentSize --];
                    /*從表頭開始將新的二叉樹進行重新排序*/
                    presort_BinaryHeap(heap, 1);

                    return ret;
            }

        測試代碼:

         

            #include "binaryheap.h"
            #include <stdio.h>
            #include <time.h>

            void print_binaryheap(BinaryHeap_handle_t heap)
            {
                    int i = 0;

                    assert(heap != NULL && heap->parray != NULL);

                    for(i = 1; i <= heap->currentSize; ++ i)
                    {
                            if(i %6)
                                    printf("%d\t",heap->parray[i]);
                            else
                                    printf("\n%d\t",heap->parray[i]);
                    }
                    printf("\n");
            }

            int main()
            {
                    int i = 0;
                    int value = 0;

                    srand((int)time(0));
                    printf("********Test Binaryheap**************\n");

                    BinaryHeap_t bheap;
                    BinaryHeap_handle_t *pheap = NULL;

                    printf("init and alloc test:\n");
                    if(init_BinaryHeap(&bheap,10))
                   {
                            printf("init_BinaryHeap() successed!\n");
                    }
                    if (alloc_BinaryHeap(&pheap,15));
                    {
                            printf("alloc_BInaryHeap() successed!\n");
                    }

                    printf("***insert test*****\n");
                    for(; i < 10; ++ i)
                    {
                            if(!insert(&bheap,5 * i - rand()%20))
                            {
                                    printf("i = %d:insert failed !!\n",i);
                            }
                    }
                    for(i = 0; i < 15; ++ i)
                    {
                            if(!insert(pheap,i * 8 - rand()%20))
                            {
                                    printf("i = %d:insert failed!!\n",i);
                            }
                    }

                    print_binaryheap(&bheap);
                    print_binaryheap(pheap);

                    printf("****deleteMin test****\n");
                    for(i = 0; i < 5; ++ i)
                    {
                            value = deleteMin(&bheap);
                            printf("bheap deleted:%d\n",value);
                            value = deleteMin(pheap);
                            printf("pheap deleted:%d\n",value);
                    }
                    print_binaryheap(&bheap);
                    print_binaryheap(pheap);

                    printf("deleteMin test successed\n");

                    printf("****delete and free test:*******\n");
                    delete_BinaryHeap(&bheap);

                    printf("Is the bheap empty ? %s\n",
                                    isEmpty(&bheap)?"Yes":"No");

                    free_BinaryHeap(&pheap);

                    printf("*********Test successed!***********\n");
                    pheap = NULL;
                    return 0;
            }

        測試結果:

         

            [gong@Gong-Computer c_binaryheap]$ ./testbinaryheap
            ********Test Binaryheap**************
            init and alloc test:
            init_BinaryHeap()
            alloc_BInaryHeap()
            ***insert test*****
            -11    -9    -9    14    15   
            10    21    23    40    26   
            -16    2    14    20    13   
            21    33    49    61    67    76   
            86    83    95    109   
            ****deleteMin test****
            bheap deleted:-11
            pheap deleted:-16
            bheap deleted:-9
            pheap deleted:2
            bheap deleted:-9
            pheap deleted:13
            bheap deleted:10
            pheap deleted:14
            bheap deleted:14
            pheap deleted:20
            15    23    21    40    26   
            21    49    21    61    67   
            76    33    95    83    109   
            deleteMin test successed
            ****delete and free test:*******
            Is the bheap empty ? Yes
            *********Test


        從上面的測試結果可知,基本上實現了二叉堆的基本插入、刪除操作。代碼的關鍵點在于刪除中的下慮和插入過程中的上慮操作。以及如何判斷代碼是否存在右兒子,如何充分運用二叉堆的特性。

        關閉窗口

        相關文章

        欧美性色欧美精品视频,99热这里只有精品mp4,日韩高清亚洲日韩精品一区二区,2020国自产拍精品高潮