数据结构学习笔记(六)堆-优先队列

基础知识

什么是堆?为什么要建立堆这种数据结构?堆的实际用处是?(堆排序)

应该采用哪种存储结构来存储堆?
因为要使堆的插入、删除等各种基本操作效率最高,所以采用完全二叉树的形式存储堆。

完全二叉树的一些重要性质:

  • 若父节点序号为i,则左儿子序号为2i,右儿子序号为2i+1。
  • 若某儿子序号为i,则其父节点序号为[i/2](取整)。

怎样插入元素到堆中呢?
假如是最大堆,删除最大元素即删除根节点,那么就会破坏树的有序性,应该怎样调整呢?

/*优先队列:堆*/

#include <cstdio>
#include <cstdlib>
#include <iostream>
#define MAX 1001
#define MinNum -10001
#define TURE 1
using namespace std;

typedef int DataType;
typedef struct HeapNode *MinHeap;
struct HeapNode {
  DataType *Elements;
  int size;
  int capacity;
};

bool IsFull(MinHeap H) { return (H->size == H->capacity); }

bool IsEmpty(MinHeap H) { return (H->size == 0); }

MinHeap CreateHeap(int N) {
  MinHeap H = (MinHeap)malloc(sizeof(struct HeapNode));
  H->Elements = (DataType *)malloc((MAX + 1) * sizeof(DataType));
  H->size = 0;
  H->capacity = MAX;
  H->Elements[0] = MinNum; //作为哨兵
  return H;
}

void Insert(MinHeap H, DataType X) {
  if (IsFull(H))
    return;
  int i = ++H->size;
  for (; X <= H->Elements[i / 2]; i = i / 2) {
    H->Elements[i] = H->Elements[i / 2];
  }
  H->Elements[i] = X;
  // return TURE;
}

void PrecDown(MinHeap H, int p) {
  int Parent, Child;
  DataType X;
  X = H->Elements[p]; /* 取出根结点存放的值 */
  for (Parent = p; Parent * 2 <= H->size; Parent = Child) {
    Child = Parent * 2;
    if ((Child != H->size) && (H->Elements[Child] > H->Elements[Child + 1]))
      Child++; /* Child指向左右子结点的较xiao者 */
    if (X <= H->Elements[Child])
      break; /* 找到了合适位置 */
    else     /* 下滤X */
      H->Elements[Parent] = H->Elements[Child];
  }
  H->Elements[Parent] = X;
}

void BuildHeap(MinHeap H) {
  int i;
  for (i = H->size / 2; i > 0; i--) {
    PrecDown(H, i);
  }
}

void PrintHeap(MinHeap H, int M) {
  int i;
  for (i = M; H->Elements[i] != H->Elements[1];) {
    printf("%d ", H->Elements[i]);
    i = i / 2;
  }
}

int main() {
  int i, X, M, N;
  int leaf;
  // int heapNode[MAX];
  scanf("%d %d", &N, &M);
  MinHeap H = CreateHeap(N);
  for (i = 0; i < N; i++) {
    scanf("%d", &X);
    Insert(H, X);
  }
  // BuildHeap(H);
  for (i = 0; i < M; i++) {
    scanf("%d", &leaf);
    printf("%d ", H->Elements[leaf]);
    while (leaf > 1) {
      leaf = leaf / 2;
      printf(" %d", H->Elements[leaf]);
    }
    printf("\n");
  }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值