Mastering Algorithms with C(heap)

(1)heap.h

/*****************************************************************************
*                                                                            *
*  -------------------------------- heap.h --------------------------------  *
*                                                                            *
*****************************************************************************/

#ifndef HEAP_H
#define HEAP_H

/*****************************************************************************
*                                                                            *
*  Define a structure for heaps.                                             *
*                                                                            *
*****************************************************************************/

typedef struct Heap_ {

int                size; // 堆的大小

int                (*compare)(const void *key1, const void *key2);
void               (*destroy)(void *data);

void               **tree; // 指向指針數組的首地址

} Heap;

/*****************************************************************************
*                                                                            *
*  --------------------------- Public Interface ---------------------------  *
*                                                                            *
*****************************************************************************/

void heap_init(Heap *heap, int (*compare)(const void *key1, const void *key2),
   void (*destroy)(void *data));

void heap_destroy(Heap *heap);

int heap_insert(Heap *heap, const void *data);

int heap_extract(Heap *heap, void **data);

#define heap_size(heap) ((heap)->size)

#endif

(2)heap.c

/*****************************************************************************
*                                                                            *
*  -------------------------------- heap.c --------------------------------  *
*                                                                            *
*****************************************************************************/

#include <stdlib.h>
#include <string.h>

#include "heap.h"

/*****************************************************************************
*                                                                            *
*  Define private macros used by the heap implementation.                    *
*                                                                            *
*****************************************************************************/

#define heap_parent(npos) ((int)(((npos) - 1) / 2))

#define heap_left(npos) (((npos) * 2) + 1)

#define heap_right(npos) (((npos) * 2) + 2)

/*****************************************************************************
*                                                                            *
*  ------------------------------- heap_init ------------------------------  *
*                                                                            *
*****************************************************************************/

void heap_init(Heap *heap, int (*compare)(const void *key1, const void *key2),
   void (*destroy)(void *data)) {

/*****************************************************************************
*                                                                            *
*  Initialize the heap.                                                      *
*                                                                            *
*****************************************************************************/

heap->size = 0;
heap->compare = compare;
heap->destroy = destroy;
heap->tree = NULL;

return;

}

/*****************************************************************************
*                                                                            *
*  ----------------------------- heap_destroy -----------------------------  *
*                                                                            *
*****************************************************************************/

void heap_destroy(Heap *heap) {

int                i;

/*****************************************************************************
*                                                                            *
*  Remove all the nodes from the heap.                                       *
*                                                                            *
*****************************************************************************/

if (heap->destroy != NULL) {

   for (i = 0; i < heap_size(heap); i++) {

      /***********************************************************************
      *                                                                      *
      *  Call a user-defined function to free dynamically allocated data.    *
      *                                                                      *
      ***********************************************************************/

      heap->destroy(heap->tree[i]);

   }

}

/*****************************************************************************
*                                                                            *
*  Free the storage allocated for the heap.                                  *
*                                                                            *
*****************************************************************************/

free(heap->tree);

/*****************************************************************************
*                                                                            *
*  No operations are allowed now, but clear the structure as a precaution.   *
*                                                                            *
*****************************************************************************/

memset(heap, 0, sizeof(Heap));

return;

}

/*****************************************************************************
*                                                                            *
*  ------------------------------ heap_insert -----------------------------  *
*                                                                            *
*****************************************************************************/

int heap_insert(Heap *heap, const void *data) {

void               *temp;

int                ipos,
                   ppos;

/*****************************************************************************
*                                                                            *
*  Allocate storage for the node.                                            *
*                                                                            *
*****************************************************************************/

// 使用realloc重新分配數組大小
if ((temp = (void **)realloc(heap->tree, (heap_size(heap) + 1) * sizeof
   (void *))) == NULL) {

   return -1;

   }

else {

   heap->tree = temp; // 指向新的地址,原有數據保持不變

}

/*****************************************************************************
*                                                                            *
*  Insert the node after the last node.                                      *
*                                                                            *
*****************************************************************************/

heap->tree[heap_size(heap)] = (void *)data; // 添加新數據

/*****************************************************************************
*                                                                            *
*  Heapify the tree by pushing the contents of the new node upward.          *
*                                                                            *
*****************************************************************************/

ipos = heap_size(heap); // 當前結點的索引
ppos = heap_parent(ipos); // 當前結點的父節點

// 大根堆
while (ipos > 0 && heap->compare(heap->tree[ppos], heap->tree[ipos]) < 0) {

	// 孩子結點的值大於父節點的值
   /**************************************************************************
   *                                                                         *
   *  Swap the contents of the current node and its parent.                  *
   *                                                                         *
   **************************************************************************/
   // 交換父節點和孩子結點的位置
   temp = heap->tree[ppos];
   heap->tree[ppos] = heap->tree[ipos];
   heap->tree[ipos] = temp;

   /**************************************************************************
   *                                                                         *
   *  Move up one level in the tree to continue heapifying.                  *
   *                                                                         *
   **************************************************************************/
   // 遞歸調整
   ipos = ppos;
   ppos = heap_parent(ipos);

}

/*****************************************************************************
*                                                                            *
*  Adjust the size of the heap to account for the inserted node.             *
*                                                                            *
*****************************************************************************/

heap->size++; // 數目加一

return 0;

}

/*****************************************************************************
*                                                                            *
*  ----------------------------- heap_extract -----------------------------  *
*                                                                            *
*****************************************************************************/

int heap_extract(Heap *heap, void **data) {

void               *save,
                   *temp;

int                ipos,
                   lpos,
                   rpos,
                   mpos;

/*****************************************************************************
*                                                                            *
*  Do not allow extraction from an empty heap.                               *
*                                                                            *
*****************************************************************************/

if (heap_size(heap) == 0) // 空堆返回
   return -1;

/*****************************************************************************
*                                                                            *
*  Extract the node at the top of the heap.                                  *
*                                                                            *
*****************************************************************************/

*data = heap->tree[0]; // 取堆頂的數據

/*****************************************************************************
*                                                                            *
*  Adjust the storage used by the heap.                                      *
*                                                                            *
*****************************************************************************/

save = heap->tree[heap_size(heap) - 1]; // 最後一個位置的數據

if (heap_size(heap) - 1 > 0) {

   if ((temp = (void **)realloc(heap->tree, (heap_size(heap) - 1) * sizeof
      (void *))) == NULL) {

      return -1;

      }

   else { // 因爲重新分配了內存,因此需要保存最後一個位置的數據

      heap->tree = temp;

   }

   /**************************************************************************
   *                                                                         *
   *  Adjust the size of the heap to account for the extracted node.         *
   *                                                                         *
   **************************************************************************/

   heap->size--; // 調整數量

   }

else { // 提出堆頂的元素後,堆爲空

   /**************************************************************************
   *                                                                         *
   *  Manage the heap when extracting the last node.                         *
   *                                                                         *
   **************************************************************************/

   free(heap->tree);
   heap->tree = NULL;
   heap->size = 0;
   return 0;

}

/*****************************************************************************
*                                                                            *
*  Copy the last node to the top.                                            *
*                                                                            *
*****************************************************************************/

heap->tree[0] = save; // 將最後一個位置的數據放到堆頂

/*****************************************************************************
*                                                                            *
*  Heapify the tree by pushing the contents of the new top downward.         *
*                                                                            *
*****************************************************************************/

ipos = 0; // 當前位置
lpos = heap_left(ipos); // 左孩子結點位置
rpos = heap_right(ipos); // 右孩子結點位置

while (1) {

   /**************************************************************************
   *                                                                         *
   *  Select the child to swap with the current node.                        *
   *                                                                         *
   **************************************************************************/

   lpos = heap_left(ipos); // 左孩子結點位置
   rpos = heap_right(ipos); // 右孩子結點位置

   if (lpos < heap_size(heap) && heap->compare(heap->tree[lpos], heap->
      tree[ipos]) > 0) {
      // 左孩子的值大於父節點的值
      mpos = lpos;

      }

   else {

      mpos = ipos;

   }

   if (rpos < heap_size(heap) && heap->compare(heap->tree[rpos], heap->
      tree[mpos]) > 0) {
      // 右孩子的值同時大於父節點和左孩子的值
      mpos = rpos;

   }

   /**************************************************************************
   *                                                                         *
   *  When mpos is ipos, the heap property has been restored.                *
   *                                                                         *
   **************************************************************************/

   if (mpos == ipos) { // 當前位置的值在父左右結點中值時最大的

      break;

      }

   else { // 將最大的位置放到父節點

      /***********************************************************************
      *                                                                      *
      *  Swap the contents of the current node and the selected child.       *
      *                                                                      *
      ***********************************************************************/

      temp = heap->tree[mpos];
      heap->tree[mpos] = heap->tree[ipos];
      heap->tree[ipos] = temp;

      /***********************************************************************
      *                                                                      *
      *  Move down one level in the tree to continue heapifying.             *
      *                                                                      *
      ***********************************************************************/

      ipos = mpos; // 繼續判斷被交換的結點

   }

}

return 0;

}

(3)ex-1.c

/*****************************************************************************
*                                                                            *
*  ex-1.c                                                                    *
*  ======                                                                    *
*                                                                            *
*  Description: Illustrates using a heap (see Chapter 10).                   *
*                                                                            *
*****************************************************************************/

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

#include "heap.h"

/*****************************************************************************
*                                                                            *
*  ------------------------------ print_heap ------------------------------  *
*                                                                            *
*****************************************************************************/

static void print_heap(Heap *heap) {

int                i;

/*****************************************************************************
*                                                                            *
*  Display the heap using in level order.                                    *
*                                                                            *
*****************************************************************************/

fprintf(stdout, "Heap size is %d\n", heap_size(heap));

for (i = 0; i < heap_size(heap); i++)
   fprintf(stdout, "Node=%03d\n", *(int *)heap->tree[i]);

return;

}

/*****************************************************************************
*                                                                            *
*  ------------------------------ compare_int -----------------------------  *
*                                                                            *
*****************************************************************************/

static int compare_int(const void *int1, const void *int2) {

/*****************************************************************************
*                                                                            *
*  Compare two integers.                                                     *
*                                                                            *
*****************************************************************************/

if (*(const int *)int1 > *(const int *)int2)
   return 1;
else if (*(const int *)int1 < *(const int *)int2)
   return -1;
else
   return 0;

}

/*****************************************************************************
*                                                                            *
*  --------------------------------- main ---------------------------------  *
*                                                                            *
*****************************************************************************/

int main(int argc, char **argv) {

Heap               heap;

void               *data;

int                intval[30],
                   i;

/*****************************************************************************
*                                                                            *
*  Initialize the heap.                                                      *
*                                                                            *
*****************************************************************************/

heap_init(&heap, compare_int, NULL);

/*****************************************************************************
*                                                                            *
*  Perform some heap operations.                                             *
*                                                                            *
*****************************************************************************/

i = 0;

intval[i] = 5;
fprintf(stdout, "Inserting %03d\n", intval[i]);
if (heap_insert(&heap, &intval[i]) != 0)
   return 1;
print_heap(&heap);
i++;

intval[i] = 10;
fprintf(stdout, "Inserting %03d\n", intval[i]);
if (heap_insert(&heap, &intval[i]) != 0)
   return 1;
print_heap(&heap);
i++;

intval[i] = 20;
fprintf(stdout, "Inserting %03d\n", intval[i]);
if (heap_insert(&heap, &intval[i]) != 0)
   return 1;
print_heap(&heap);
i++;

intval[i] = 1;
fprintf(stdout, "Inserting %03d\n", intval[i]);
if (heap_insert(&heap, &intval[i]) != 0)
   return 1;
print_heap(&heap);
i++;

intval[i] = 25;
fprintf(stdout, "Inserting %03d\n", intval[i]);
if (heap_insert(&heap, &intval[i]) != 0)
   return 1;
print_heap(&heap);
i++;

intval[i] = 22;
fprintf(stdout, "Inserting %03d\n", intval[i]);
if (heap_insert(&heap, &intval[i]) != 0)
   return 1;
print_heap(&heap);
i++;

intval[i] = 9;
fprintf(stdout, "Inserting %03d\n", intval[i]);
if (heap_insert(&heap, &intval[i]) != 0)
   return 1;
print_heap(&heap);
i++;

while (heap_size(&heap) > 0) {

   if (heap_extract(&heap, (void **)&data) != 0)
      return 1;
   fprintf(stdout, "Extracting %03d\n", *(int *)data);
   print_heap(&heap);

}

/*****************************************************************************
*                                                                            *
*  Destroy the heap.                                                         *
*                                                                            *
*****************************************************************************/

fprintf(stdout, "Destroying the heap\n");
heap_destroy(&heap);

return 0;

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章