DSAA之PRIORITY QUEUES 实现(二)

1. 回顾

  上一篇记录了优先级堆的一些基本概念,和基本删除插入操作的特点,本篇开始具体实现。DSAA给出了一些实现,笔者做了些改变,舍弃数组[0]为空的策略。

2. 代码展示

#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#define element_type  int
#define MAX_BUF 30
#define maxsize 10

struct heap_struct{
    /* Maximum # that can fit in the heap */
    unsigned int max_heap_size;
    /* heap中最后一个位置 */
    unsigned int size;
    element_type *elements;
};

typedef struct heap_struct * PRIORITY_QUEUE;

PRIORITY_QUEUE create_pq( unsigned int max_elements );
void insert( element_type x, PRIORITY_QUEUE H );
void Build_heap(element_type * x, int size,PRIORITY_QUEUE H);
element_type delete_min( PRIORITY_QUEUE H );

int main(){
   PRIORITY_QUEUE p_q;
   element_type data[MAX_BUF];
   int i,j;
   printf("please input your own data:\n");
   for(i=0;i<maxsize;i++)
      scanf("%d",&data[i]);
   p_q=create_pq(MAX_BUF);
   Build_heap(data,maxsize,p_q);
   for(i=0,j=2;i<=p_q->size;i++){
      printf("%d ",(p_q->elements)[i]);
      if(i== j-2){
          printf("\n");
      j*=2;
      }
   }
   printf("\n");

   printf("choose a number to insert :\n");
   scanf("%d",&data[0]);
   insert(data[0],p_q);

   for(i=0,j=2;i<=p_q->size;i++){
      printf("%d ",(p_q->elements)[i]);
      if(i== j-2){
          printf("\n");
      j*=2;
      }
   }
   printf("\n");

   printf("first delete_min: %d\n",delete_min(p_q));

   for(i=0,j=2;i<=p_q->size;i++){
      printf("%d ",(p_q->elements)[i]);
      if(i== j-2){
          printf("\n");
      j*=2;
      }
   }
   printf("\n");

}



PRIORITY_QUEUE create_pq( unsigned int max_elements ){
    PRIORITY_QUEUE H;
    H = (PRIORITY_QUEUE) malloc ( sizeof (struct heap_struct) );
    if( H == NULL )
        errx(1,"Out of space!!!");
    //这里笔者并没有在数组空出来第一个元素
    H->elements = (element_type *) malloc(( max_elements) * sizeof (element_type));
    if( H->elements == NULL )
        errx(1,"Out of space!!!");
    H->max_heap_size = max_elements;
    H->size = -1;
    return H;
}

void insert( element_type x, PRIORITY_QUEUE H ){
    unsigned int i;
    if( H->max_heap_size == H->size +1)
        errx(1,"Priority queue is full");
    else{
        //更新当前size,及将i指向新插入的节点的位置
        i = ++H->size;
        //找当前节点的父代,如果比当前节点大,则需要向上渗透
        while( i!=0 && H->elements[(i-1)/2] > x ){
            //将当前节点的父代和当前节点的值互换
            H->elements[i] = H->elements[(i-1)/2];
            //笔者会这么处理:
            //tmp = H->elements[i];
            //H->elements[i] = H->elements[(i-1)/2];
            //H->elements[(i-1)/2]=tmp;
            //DSAA的处理比较巧妙,因为x的值是我们一直都知道的
            i = (i-1)/2;
            //因为笔者不将数组的第一个元素空出来,所以要加下面的语句

        }
        H->elements[i] = x;
    }
}
void Build_heap(element_type * x, int size,PRIORITY_QUEUE H){
    int i;
    for(i=0;i<size;i++)
        insert(x[i],H);
}

element_type delete_min( PRIORITY_QUEUE H ){
    unsigned int i, child;
    element_type min_element, last_element;
    if( H->size == -1 )
        errx(1,"Priority queue is empty");
    min_element = H->elements[0];
    last_element = H->elements[H->size--];
    //debug
    //printf("last_element %d\n",last_element);
    //向下渗透,从i=0开始
    for( i=0; i*2+1 <= H->size;  ){
        //每次找当前节点的子代,有可能是单子代
        child = i*2+1;
        //第一个逻辑判断是否当了最后一个元素,因为只有最后一个元素才可能有单子代的情况。
        //否则判断左右子代的Key值大小,决定渗透的方向
        if( ( child != H->size ) &&( H->elements[child+1] < H->elements [child] ) )
            //如果是右子代的话,要正确更新chlid,使其指向右子代
            child++;
        //这里的逻辑,需要仔细思考,如果最后一位元素比当前chlid的值大
        //则证明还需要继续给最后一个元素找合适的插入位置。
        if( last_element > H->elements[child] ){
            //将chlid的元素放到当前i的位置,同时child复制给i,重复上面的工作,此时
            //也可以像笔者Inser函数提到的,互换i和child的值,但是我们一直知道最后一
            //个元素的值,所以可以直接这么简化
            H->elements[i] = H->elements[child];
            i=child;
    }
        else
            //直接找到了合适的位置,向下渗透结束,也就是最后一个元素插入到当前的i的位置
            break;
    }
    H->elements[i] = last_element;
    return min_element;
}

3. 结果

[root@localhost ~]# ./6_1
please input your own data:
13 21 16 24 31 19 68 65 26 32
13 
21 16 
24 31 19 68 
65 26 32 
choose a number to insert :
14   #这是自己输入的数字回显
13 
14 16 
24 21 19 68 
65 26 32 31 
first delete_min: 13
14 
21 16 
24 31 19 68 
65 26 32 
[root@localhost ~]#

这里写图片描述
这里写图片描述
  
  上面两个图,直接验证了插入的正确性,然后删除的正确性需要自己动手画下。笔者之前的打印输出也能直观的看出来,其实也不用画图验证了。最后具体的思考细节详细的记录在代码的批注里面,这里就不赘述了。

猜你喜欢

转载自blog.csdn.net/lovestackover/article/details/80182850