1. 程式人生 > >堆的建立,插入,刪除,排序

堆的建立,插入,刪除,排序

    堆是一種完全二叉樹,有最小堆和最大堆之分,最小堆是指根節點的值一定小於左子樹和右子樹所有元素的值,最大堆則相反(當你從小到大排序時, 可以選擇最小堆反之,則選擇最大堆)
    
    1.如何建立一個最小堆呢:由於堆是一個完全二叉樹,所以滿足以下關係(我們將元素的順序從0開始排,第i個節點稱之為Ki, 那麼元素就有K0, K1, K2.....),Ki的父節點一定是K(i-1)/2, Ki的左孩子節點一定是Ki*2+1, 右孩子節點一定是Ki*2+2。因此我們可以不用向普通二叉樹那樣,用指標來訪問其左孩子節點和右孩子節點(本次程式中是以指標來訪問的,雖然有點多此一舉,就當鍛鍊一下自己使用指標的能力吧)。然而最重要的問題是,假如我們一開始面臨的是一個堆,我們又如何將其變成一個最小堆呢,那就需要我們進行向上調整(後面會具體講)
    
    2.如何在一個最小堆中插入一個元素呢: 為了不破壞堆已有的結構,在堆尾部插入一個元素後,會破壞堆的結構,如何進行調整呢?可以採用向上調整
    
   3.如何刪除一個元素呢:堆就像是一個佇列,在尾部插入,在頭部刪除,再刪除掉整個樹的根節點後,會破壞堆的結構,為了有效利用堆已有的結構,將堆尾部的元素移到根節點位置,然後進行向下調整(後面會講向下調整)
   
    4.向下調整:將尾部節點移到根節點位置,若該節點數值小於左孩子節點和有孩子節點數值,就無需調整,否則就需將數值最小的孩子節點與根節點互換元素值,然後對數值發生改變的孩子節點進行同樣的調整。(堆的優異性就體現在這裡,對於數值沒有發生改變的孩子節點就無需進行調整,這很可能一下子跳過了一大堆節點,所以二叉樹的時間複雜性與數的高度有關)
    
   5.向上調整:在尾部插入一個元素後,將該元素與其父節點比,若父節點的值大於該孩子節點,則進行互換元素值,對於堆來說,假如有n個節點,則有n / 2個節點是有孩子節點的,則K0至Kn/2都需要進行調整,注意是從Kn/2至K0的順序來依此調整的,從樹的結構來看就是先上的,同時當改變孩子節點元素值是,若該孩子節點同時也有孩子時要進行向下調整,由於堆無非是根,左孩子和右孩子,可以通過遞迴來實現,所以程式碼不是太複雜
   
    關於調整的總結:我們可以發現向上調整和向下調整大致思路是一樣的,都是比較根節點與其孩子節點數值的大小以保證最小堆(或最大堆)的要求,所不同的是向上調整與向上調整的調整方向是相反的,向上調整是在尾部插入元素要進行的調整,向下調整是在刪除根節點並將尾部節點補為根節點後要進行的調整
    
    6.堆的一個應用就是進行排序:由於根節點的元素值是整個樹的最小的,我們可以建立一個堆後,刪除該根節點,將餘下的節點進行向下調整,得到新的堆,重新進行上述步驟。就可以得到從小到大排列的結果了(從大到小隻需建立最大堆即可)。
#include <stdio.h>
#include <stdlib.h>

#define SIZE 20


typedef int ElemType;
typedef struct treenode
{
    ElemType data;
    struct treenode * left;
    struct treenode * right;
}Node, *pNode;

void show(pNode * tree)
{
    if (tree == NULL)
        return ;
    int i;
    for (i = 0; tree[i] != NULL; i++)
        printf("%-3d", tree[i]->data);
    printf("\n");
}
void getlength(pNode * tree)
{
    if (tree == NULL)
        printf("get length failure\n");;
    int i;
    for (i  = 0; tree[i] != NULL; i++) ;
        printf("tree has %d nodes\n", i);
}
pNode * CreateTree(ElemType *e, int length)
{
    if (e == NULL || length <= 0 || length > SIZE)
        return ;
    pNode *str = (pNode *)malloc(sizeof(pNode) * SIZE);
    int i, j;
    for ( i = 0; i < length; i++)
    {
        str[i] = (pNode)malloc(sizeof(Node) * 1);
        if (str[i] == NULL)
        {
            for (j = 0; j < i; j++)
            {
                free(str[j]);
            }
            free(str);
            printf("堆建立失敗\n");
            return NULL;
        }
        else
            str[i]->data = e[i];
    }

       for (i = 0; i < length; i++)
    {
        if (2 * i + 1 < length)
            str[i]->left = str[2 * i + 1];
        else
            str[i]->left = NULL;
        if (2 * i + 2 < length)
            str[i]->right = str[2 * i + 2];
        else
            str[i]->right = NULL;
    }
    return str;
}
void ExchangeData(ElemType *a, ElemType * b)
{
    if (a == NULL || b == NULL)
        return;
    printf("exchange %d and %d\n", *a, *b);
    ElemType temp;
    temp = *a;
    *a = *b;
    *b = temp;
}
void SiftUp(pNode root)
{
    if (root == NULL || (root->left ==  NULL && root->right == NULL))
        return;
    ElemType e;
    int c;
    if (root->left == NULL)
    {
        c = 0;
        e = root->right->data;
    }
    else if(root->right == NULL)
    {
        c = 1;
        e = root->left->data;
    }
    else
    {
        c = root->left->data > root->right->data? 0 : 1;
        e = root->left->data > root->right->data? root->right->data : root->left->data;
    }
    if (root->data > e)
    {
        if (c == 0)
        {
            ExchangeData(&(root->data), &(root->right->data));
            SiftUp(root->right);
         }
        else if (c == 1)
        {
            ExchangeData(&(root->data), &(root->left->data));
            SiftUp(root->left);
          }
    }
}
 void SiftDown(pNode root)
{
    if (root == NULL || (root->left == NULL && root->right == NULL))
        return;
    ElemType e;
    int c;
    if (root->left == NULL)
    {
        c = 0;
        e = root->right->data;
    }
    else if(root->right == NULL)
    {
        c = 1;
        e = root->left->data;
    }
    else
    {
        c = root->left->data > root->right->data ? 0 : 1;
        e = root->left->data > root->right->data? root->right->data : root->left->data;
    }
        if (root->data > e)
    {
        if (c == 0)
        {
            ExchangeData(&(root->data), &(root->right->data));
            SiftDown(root->right);
        }
        else if (c == 1)
        {
            ExchangeData(&(root->data), &(root->left->data));
            SiftDown(root->left);
        }
    }
}
 void Delete(pNode * tree)
{
    if (tree == NULL || tree[0] == NULL)
        return;
    int i;
    for (i = 0; tree[i] != NULL; i++) ;
    i--;
    if (i == 0)
    {
        free(tree[0]);
        return;
    }
    tree[0]->data = tree[i]->data;
    free(tree[i]);
    tree[i] = NULL;
    if (i % 2 == 1)
        tree[(i - 1) / 2]->left = NULL;
    else
        tree[(i - 1) / 2]->right = NULL;
    SiftDown(tree[0]);
}

 void Insert(pNode *tree, ElemType e)
{
    if (tree == NULL)
    {
        printf("insert failure\n");
        return ;
    }
    int i, j;
    for ( i = 0; tree[i] != NULL; i++);
    if (i > SIZE)
    {
        printf("insert failure\n");
        return;
    }
    printf("i = %d\n", i);
    tree[i] = (pNode)malloc(sizeof(Node) * 1);
    if (tree[i] == NULL)
    {
        printf("insert failure\n");
        return;
    }
    tree[i]->data = e;
    tree[i]->left = NULL;
    tree[i]->right = NULL;
    if (i % 2 == 1)
        tree[(i - 1) / 2]->left = tree[i];
    else
        tree[(i - 1) / 2]->right = tree[i];
    for (j = (i + 1) / 2 - 1; j >= 0; j--)
        SiftUp(tree[j]);
}
int main()
{
    ElemType res[SIZE];
    int i;
    ElemType e;
    ElemType a[SIZE] = {2, 5, 6, 23, 45, 55, 67, 32, 56, 11, 1};
/*  printf("please input 10 numbers\n");
    for (i = 0; i < 10; i++)
        scanf("%d", a + i);
*/
    pNode * tree = CreateTree(a, 10);
    if (tree == NULL)
    {
        printf("create tree failure\n");
        exit(1);
    }
    for (i = 10 / 2 - 1; i >= 0; i--)
        SiftUp(tree[i]);
    show(tree);
    for(i = 0; i < 5; i++)
    {
        printf("please input the num which you want to insert\n");
        scanf("%d", &e);
        Insert(tree, e);
        show(tree);
    }
int main()
{
    ElemType res[SIZE];
    int i;
    ElemType e;
    ElemType a[SIZE] = {2, 5, 6, 23, 45, 55, 67, 32, 56, 11, 1};
/*  printf("please input 10 numbers\n");
    for (i = 0; i < 10; i++)
        scanf("%d", a + i);
*/
    pNode * tree = CreateTree(a, 10);
    if (tree == NULL)
    {
        printf("create tree failure\n");
        exit(1);
    }
    for (i = 10 / 2 - 1; i >= 0; i--)
        SiftUp(tree[i]);
    show(tree);
    for(i = 0; i < 5; i++)
    {
        printf("please input the num which you want to insert\n");
        scanf("%d", &e);
        Insert(tree, e);
        show(tree);
    }