DSAA之Leftist Heaps(二)

1. 回顾

  根据上一篇DSAA之Leftist Heaps(一)的理论,可以很快写出来相应的函数。

2. 左倾堆的实现

#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#define maxsize 10
typedef struct node {
    struct node * left;
    struct node * right;
    int npl;
    int key;
} NODE;
typedef NODE * Leftist_Heaps;
Leftist_Heaps merge(Leftist_Heaps L,Leftist_Heaps R);
Leftist_Heaps build_heap(int * x, int size,Leftist_Heaps  H);
Leftist_Heaps insert(int key, Leftist_Heaps L);
int delete_min(Leftist_Heaps * H);
void printf_inorder(Leftist_Heaps H);
void printf_postorder(Leftist_Heaps H);


int main(void){
  Leftist_Heaps leftheaps=NULL;
  int data[maxsize];
  int i;
  printf("please input your own data:\n");
  for(i=0;i<maxsize/2;i++)
    scanf("%d",&data[i]);
  leftheaps=build_heap(data,maxsize/2,leftheaps);
  printf("inorder : ");
  printf_inorder(leftheaps);
  printf("\n");
  printf("postorder : ");
  printf_postorder(leftheaps);
  printf("\n");
  printf("choose a number to insert :\n");
  scanf("%d",&data[0]);
  leftheaps=insert(data[0],leftheaps);
  printf("inorder : ");
  printf_inorder(leftheaps);
  printf("\n");
  printf("postorder : ");
  printf_postorder(leftheaps);
  printf("\n");
  printf("delete_min: %d\n",delete_min(&leftheaps));
  printf("inorder : ");
  printf_inorder(leftheaps);
  printf("\n");
  printf("postorder : ");
  printf_postorder(leftheaps);
  printf("\n");
}

Leftist_Heaps build_heap(int * x, int size,Leftist_Heaps  H){
    int i;
    for(i=0;i<size;i++){
      H=insert(x[i],H);
    }
    return H;
}

Leftist_Heaps insert(int key, Leftist_Heaps L){
   Leftist_Heaps R;
   if((R=calloc(1,sizeof(NODE))) == NULL)
      errx(1,"error in calloc\n");
   R->key=key;
   return merge(L,R);
}

int delete_min(Leftist_Heaps * H){
   Leftist_Heaps L,R;
   int key=(*H)->key;
   L=(*H)->left;
   R=(*H)->right;
   free(*H);
   *H=merge(L,R);
   return key;
}

Leftist_Heaps merge(Leftist_Heaps L,Leftist_Heaps R){
    Leftist_Heaps little,big,temp;
    //两者合并的树其中有一个为NULL,直接返回另一个,这里也处理了两者都为NULL的情况
    if(L == NULL)
        return R;
    else if (R == NULL)
        return L;
    //预处理
    if(L->key > R->key){
        little=R;
        big=L;
    }
    else{
        little=L;
        big=R;
    }
    if(little->left == NULL){
    //无需判断,直接互换左右子树
        little->left=big;
        little->npl=0;
        return little;
    }
    //靠近基准
    little->right=merge(little->right,big);

    //每次需要判断左右子树的npl是否符合左倾堆定义
    if(little->left->npl < little->right->npl){
        temp=little->left;
        little->left=little->right;
        little->right=temp;
    }
    //更新当前节点的npl信息
    little->npl=little->right->npl+1;
    //一定要返回当前节点
    return little;
}

void printf_inorder(Leftist_Heaps H){
     if( H != NULL){
         printf_inorder(H->left);
         printf("%d ",H->key);
         printf_inorder(H->right);
     }
}


void printf_postorder(Leftist_Heaps H){
     if( H != NULL){
         printf_postorder(H->left);
         printf_postorder(H->right);
         printf("%d ",H->key);
     }
}

  结果如下:

[root@localhost ~]# ./6_2
please input your own data:
0 1 2 3 4
inorder : 3 2 4 0 1
postorder : 3 4 2 1 0
choose a number to insert :
5
inorder : 3 2 4 0 5 1
postorder : 3 4 2 5 1 0
delete_min: 0
inorder : 3 2 4 1 5
postorder : 3 4 2 5 1
[root@localhost ~]#

3. 几个强调的地方

  看过DSAA的同学可以明显发现,笔者的处理逻辑和书上不同。笔者是按照前一篇总结的算法,自己撸。但是if(little->left == NULL)的代码逻辑是笔者进行debug的时候修正的。
  首先看看一种处理方式:

little->right=merge(little->right,big);
if(little->left == NULL || little->left->npl < little->right->npl){
        temp=little->left;
        little->left=little->right;
        little->right=temp;
}   
if(little->right != NULL)
    little->npl=little->right->npl+1;
else 
    little->npl=0;

  如果是在merge之后处理特殊情况时,代码运行到这里一定保证little节点的右子树非空,左子树不一定。所以处理逻辑变成还要判断一次是否左子树为空。另外最后更新npl的时候也要注意处理little->rightNULL的情况。
  第二种方式如笔者上面的:

if(little->left == NULL){
    //无需判断,直接互换左右子树
        little->left=big;
        little->npl=0;
        return little;
    }
    //靠近基准
little->right=merge(little->right,big);

  此时只要处理little->left为空的情况,就可以了。因为代码运行到判断npl的逻辑时,一定保证左右子树都不为NULL以上都是递归的实现细节考究,而非左倾堆构建的算法细节,毕竟递归只是一种编程手段。
  

猜你喜欢

转载自blog.csdn.net/lovestackover/article/details/80214737
今日推荐