優先隊列——左式堆

【0】README

0.1) 本文文字描述部分轉自 數據結構與算法分析, 旨在理解 優先隊列——左式堆 的基礎知識; 
0.2) 本文核心思路均爲原創, 源代碼部分借鑑 數據結構與算法分析 ; 
0.3) for original source code, please visit https://github.com/pacosonTang/dataStructure-algorithmAnalysis/tree/master/chapter6/p145_leftist_heap
node

1)相關定義git

  • 1.1)零路徑長度定義: 到沒有兩個兒子的節點最短距離, 即零路徑長Npl 定義爲 從 X 到一個沒有兩個兒子的 節點的最短路徑的長;也即, 非葉子節點到葉子節點的最少邊數,其中NULL的零路徑長爲-1, 葉子節點的零路徑長爲0;(乾貨——零路徑長的定義—— 非葉子節點到葉子節點的最少邊數,很是重要,由於左式堆的定義是基於零路徑長的定義的) 
    這裏寫圖片描述
    github

  • 1.2)左式堆定義:一棵具備堆序性質的二叉樹 + 零路徑長:左兒子 ≧ 右兒子 + 父節點 = min{兒子} +1;(乾貨——左式堆的定義是創建在具備堆序性的二叉樹上,而不是二叉堆上)算法

2)merge操做原則: 根值大的堆與根值小的堆的右子堆合併;(乾貨——merge操做原則) 
3)merge操做存在的三種狀況(設堆H1的根值小於H2)
數據結構

  • case1) H1只有一個節點;
  • case2) H1根無右孩子;
  • case3) H1根有右孩子;

補充(Complementary):左式堆合併操做詳解(merge)

左式堆合併原則:大根堆H2與小根堆H1的右子堆合併 (乾貨——左式堆合併原則) 
具體分三種狀況(設堆H1的根值小於H2) 
這裏寫圖片描述
post

  • case1)H1只有一個節點(只有它本身而已): H1只有一個節點,若出現不知足 零路徑長:左兒子≧右兒子,交換左右孩子; 
    這裏寫圖片描述 
    • Attention)上例中(中間所示堆),左兒子的零路徑長爲-1, 而右兒子的零路徑長爲0,因此不知足左式堆的條件, 須要交換左右孩子;
  • case2)H1根無右孩子: H1根無右孩子,若出現不知足:零路徑長:左兒子≧右兒子,須要交換左右孩子。 
    這裏寫圖片描述 
    • Attention)上例中(中間所示堆),左兒子的零路徑長爲0, 而右兒子的零路徑長爲1,因此不知足左式堆的條件,須要交換;
  • case3)H1根有右孩子: 
    • step1)截取H1的右子堆R1, 和截取H2的右子堆R2;
    • step2)將R1 與 R2進行merge操做獲得H3, 且取R1和R2中較小根做爲新根; (Attention: 如今你將看到,截取後的H1 和 H2, 以及新生成的H3 都是 case2);
    • step3)比較H3的左右孩子,是否知足左式堆要求,若是不知足則交換左右孩子;
    • step4)將H3與沒有右子堆的H1進行merge操做,也即最後將case3 轉換爲了 case2; 
      這裏寫圖片描述 
      這裏寫圖片描述

Conclusion) 如今才知道,左式堆的merge操做實際上是一個遞歸的過程, 看以下解析; (乾貨——這是最後解析merge操做啦) 

spa

Attention once again)code

  • A1)左式堆是創建在具備堆序性的二叉樹上;
  • A2)左式堆是創建在零路徑長上;
  • A3)左式堆的核心操做是 merge, 不管insert 仍是 deleteMin 都是基於 merge操做的;
  • A4)左式堆的merge操做執行後,還要update 左式堆根節點的零路徑長, 左式堆根節點的零路徑長 == min{兒子的零路徑長} +1;
  • A5) update 後, 還須要比較 左右零路徑長 是否知足左式堆的定義, 若是不知足,還須要交換左式堆根節點的左右孩子;

 


source code at a glance )blog

 

#include "leftist_heap.h" 

// swap the left and the right in priority queue.
void swap(PriorityQueue h1)
{
    PriorityQueue temp;

    temp = h1->left;
    h1->left = h1->right;
    h1->right = temp;
}

// analog print directories and files name in the BinaryTree, which involves postorder traversal. 
void printPreorder(int depth, TreeNode root)
{           
    int i;

    if(root) 
    {      
        for(i = 0; i < depth; i++)
            printf("    ");     
        printf("%d\n", root->value);
        printPreorder(depth + 1, root->left); 
         // Attention: there's difference between traversing binary tree and common tree.
        printPreorder(depth + 1, root->right);
    }
    else 
    {
        for(i = 0; i < depth; i++)
            printf("    ");     
        printf("NULL\n");
    }
}

// insert an element with value into the priority queue.
PriorityQueue insert(ElementType value, PriorityQueue pq)
{
    TreeNode node;            

    node = (TreeNode)malloc(sizeof(struct TreeNode));
    if(!node)
    {
        Error("failed inserting, for out of space !");
        return pq;
    }
    node->left = NULL;
    node->right = NULL;
    node->nullPathLen = 0;
    node->value = value;    
    
    if(pq == NULL) // means that just only creating a node with value.
    {
        return node;
    }
    else
    {
        return merge(node, pq);        
    }
}

// return the minimal between a and b.
int minimal(int a, int b)
{
    return a > b ? b : a;
}

// merge the priority queue h1 and h2.
PriorityQueue merge(PriorityQueue h1, PriorityQueue h2)
{        
    if(h1 == NULL)
    {
        return h2;
    }
    else if(h2 == NULL)
    {
        return h1;
    }    
    if(h1->value > h2->value)
    {
        return innerMerge(h2, h1);
    }
    else
    {
        return innerMerge(h1, h2);
    }    
}

// merge the priority queue h1 and h2.
PriorityQueue innerMerge(PriorityQueue h1, PriorityQueue h2)
{ 
    if(h1->left == NULL)
    {
        h1->left = h2;
    }
    else
    {
        h1->right = merge(h1->right, h2);
        
    }    
    // update the null path length
    if(h1->right == NULL)
    {
        h1->nullPathLen = 0;
    }
    else
    {
        h1->nullPathLen = minimal(h1->left->nullPathLen, h1->right->nullPathLen) + 1;    
        // exchange the left and the right
        if(h1->left->nullPathLen < h1->right->nullPathLen)
        {
            swap(h1);
        }
    }
    return h1;
}

// delete the minimal element in the priority queue.
PriorityQueue deleteMin(PriorityQueue h1)
{
    PriorityQueue left;
    PriorityQueue right;

    if(!h1)
    {
        Error("failed deleteMin, for the root doesn't point to any position!");
        return NULL;
    }
    left = h1->left;
    right = h1->right;
    free(h1);

    return merge(left, right);
}

int main()
{
    PriorityQueue h1;
    PriorityQueue h2;    
    int data[] =  {21, 10, 23, 14, 3, 26, 17, 8};    
    int data2[] = {18, 12, 33, 24, 6, 37, 7, 18};    
    int i;

    h1 = insert(data[0], NULL);
    for(i=1; i<8; i++)
    {
        h1 = insert(data[i], h1);
    }
    printf("\n=== after the leftist heap h1 is merged===\n");
    printPreorder(1, h1);

    h2 = insert(data2[0], NULL);
    for(i=1; i<8; i++)
    {
        h2 = insert(data2[i], h2);
    }
    printf("\n=== after the leftist heap h2 is merged===\n");
    printPreorder(1, h2);
     
    h1 = merge(h1, h2);
    printf("\n=== after both h1 and h2 are merged===\n");
    printPreorder(1, h1);

    h1 = deleteMin(h1);
    printf("\n=== after executing deleteMin operation ===\n");
    printPreorder(1, h1);

    return  0;
}

 


printing results are as follows) 遞歸

Attention for analog between results and the 2 images above.

這裏寫圖片描述 
這裏寫圖片描述 
這裏寫圖片描述

相關文章
相關標籤/搜索