pyzyd 发表于 2025-10-9 15:49:58

堆和优先队列

本帖最后由 pyzyd 于 2025-10-11 15:56 编辑

堆有最大堆和最小堆,

堆是完全二叉树,
要求:
1.每个父节点大于(或小于)等于其子节点,左右子节点没有大小要求
2.堆最多只能有一个单个的左子节点,不能有多个结点,不能是单个的右子节点
   90
    /\
   70   80
/ \   / \
6020 75 50

这就是一个最大堆

错误示例
   1
    / \
   2   3
/   /

堆的代码实现
/*
堆是特殊的树,
堆是完全二叉树,
堆中每一个节点的值都大于或等于其左右孩子节点的值,称为大顶堆(最大堆);
堆中每一个节点的值都小于或等于其左右孩子节点的值,称为小顶堆(最小堆)。
堆可以用数组表示,数组中第i个元素,其左孩子为2i+1,右孩子为2i+2。
*/

#include <cstring>
#include <iomanip>
#include <iostream>
#include <string>
#include <cmath>

#define DEFAULT_CAPCITY 128

typedef int DataType;

typedef struct _Heap {
    DataType *data;
    int size;
    int capacity;
} Heap;

bool initHeap(Heap &heap, int *original, int size);
bool insert(Heap &heap, DataType value);
static void buildHeap(Heap &heap);
static void adjustDown(Heap &heap, int index);
static void adjustUp(Heap &heap, int index);


int main() {
    Heap hp;
    int origVals[] = {1, 2, 3, 87, 93, 82, 92, 86, 95};
    if (!initHeap(hp, origVals, sizeof(origVals) / sizeof(origVals))) {
      std::cerr << "init heap failed!" << std::endl;
      return -1;
    }

    if (typeid(1.0) == typeid(float)) {
      std::cout << "1.0 is float" << std::endl;
    } else {
      std::cout << "1.0 is double" << std::endl;
    }
    insert(hp, 100);
    return 0;
}


bool initHeap(Heap &heap, int *original, int size) {
    if (original == nullptr || size <= 0) {
      return false;
    }
    heap.capacity = DEFAULT_CAPCITY > size ? DEFAULT_CAPCITY : size;
    heap.data = new DataType;
    if (!heap.data) {
      return false;
    }
    memcpy(heap.data, original, size * sizeof(int));
    heap.size = size;
    buildHeap(heap);
    return true;
}

bool insert(Heap &heap, DataType value) {
    if (heap.size == heap.capacity) {
      return false;
    }
    int index = heap.size++;
    heap.data = value;
    adjustUp(heap, index);
    return true;
}

/*
从最后一个非叶子结点(父节点 size / 2 - 1
的位置)逐个往前调整所有父节点(直到根节点),
确保每一个父节点都是一个最大堆,最终整个堆就是一个最大堆。
*/
static void buildHeap(Heap &heap) {
    int i;
    for (i = heap.size / 2 - 1; i >= 0; i--) {
      adjustDown(heap, i);
    }
}

/*
将当前节点和子节点调整成最大堆
*/
static void adjustDown(Heap &heap, int index) {
    int cur = heap.data;
    int parent, child;
    for (parent = index; (parent * 2 + 1) < heap.size; parent = child) {
      child = parent * 2 + 1;
      // 比较左子节点和右子节点,取较大的那个
      if ((child + 1) < heap.size &&
            heap.data < heap.data) {
            child++;
      }
      // 如果当前节点大于等于最大子节点,则不需要调整
      if (cur >= heap.data) {
            break;
      } else {
            // 否则,将当前节点和最大子节点交换
            heap.data = heap.data;
            heap.data = cur;
      }
    }
}

static void adjustUp(Heap &heap, int index) {
    if (index < 0 || index >= heap.size) {
      return;
    }
    while (index > 0) {
      int parent = (index - 1) / 2;
      if (heap.data <= heap.data) {
            break;
      }

      // 交换当前节点与父节点
      int temp = heap.data;
      heap.data = heap.data;
      heap.data = temp;

      index = parent;
    }
}

用堆来实现优先队列,利用了堆可以用数组存储的特性
#include <iostream>
#include <cstring>
#include <random>

#define DEFAULT_CAPACITY 128

typedef struct _task{
    int priority;

}Task;
typedef Task DataType;

typedef struct _PriorityQueue {
    DataType* data;
    int size;
    int capacity;
}PriorityQueue;

bool init(PriorityQueue &pq, DataType *original, int size);
bool push(PriorityQueue &pq, DataType value);
bool pop(PriorityQueue &pq, DataType &value);
bool isEmpty(PriorityQueue &pq);
bool isFull(PriorityQueue &pq);
void destroy(PriorityQueue &pq);

static void build(PriorityQueue &pq);
static void adjustDown(PriorityQueue &pq, int index);
static void adjustUp(PriorityQueue &pq, int index);

bool init(PriorityQueue &pq, DataType *original, int size) {
    if (!original || size <= 0) {
      return false;
    }
    pq.capacity = size > DEFAULT_CAPACITY ? size : DEFAULT_CAPACITY;
    pq.data = new DataType;
    // // 第一种初始化方式
    // memcpy(pq.data, original, size * sizeof(DataType));
    // pq.size = size;
    // build(pq);

    // 第二种初始化方式
    pq.size = 0;
    for (int i = 0; i < size; i++) {
      push(pq, original);
    }
    return true;
}

static void build(PriorityQueue &pq) {
    for (int i = pq.size / 2 - 1; i >= 0; i--) {
      adjustDown(pq, i);
    }
}

static void adjustDown(PriorityQueue &pq, int index) {
    DataType cur = pq.data;
    int parent = index;
    int child;
   //从当前的节点开始,向下调整子节点及子节点的子节点使数组满足堆的特性
    while (parent * 2 + 1 < pq.size) {
      child = parent * 2 + 1;
      if (child + 1 < pq.size && pq.data.priority < pq.data.priority) {
            child++;
      }
      if (pq.data.priority > cur.priority) {
            pq.data = pq.data;// 子节点上移
            parent = child;
      } else {
            break;
      }
    }
    pq.data = cur;
}

bool push(PriorityQueue &pq, DataType value) {
    if (isFull(pq)) {
      return false;
    }
    pq.data = value;
    adjustUp(pq, pq.size - 1);
    return true;
}

bool isFull(PriorityQueue &pq) {
    return pq.size == pq.capacity;
}

bool isEmpty(PriorityQueue &pq) {
    return pq.size == 0;
}

static void adjustUp(PriorityQueue &pq, int index) {
    DataType cur = pq.data;
    int child, parent;
    for (child = index; child > 0; child = parent) {
      parent = (child - 1) / 2;
      if (pq.data.priority < cur.priority) {
            pq.data = pq.data;
            pq.data = cur;
      } else {
            break;
      }
    }
}

bool pop(PriorityQueue &pq, DataType &value) {
    if (isEmpty(pq)) {
      return false;
    }
    value = pq.data;
    pq.data = pq.data[--pq.size];
    adjustDown(pq, 0);
    return true;
}

void destroy(PriorityQueue &pq) {
    delete[] pq.data;
    pq.data = nullptr;
    pq.size = pq.capacity = 0;
}

int main()
{
    std::mt19937 gen(time(0)); // random device
    std::uniform_int_distribution<int> dis(0, 9);
    PriorityQueue pq;
    Task tasks;
    for (int i = 0; i < 7; i++) {
      tasks.priority = dis(gen);
    }

    if (!init(pq, tasks, sizeof(tasks) / sizeof(Task))) {
      std::cerr << "init failed" << std::endl;
      return -1;
    }
    std::cout << "Tasks priority:" <<std::endl;
    for (int i = 0; i < pq.size; i++){
      std::cout << tasks.priority << " ";
    }
    std::cout << std::endl;
    std::cout << "Priority queue:" << std::endl;
    for (int i = 0; i < pq.size; i++){
      std::cout << pq.data.priority << " ";
    }
    std::cout << std::endl;

    push(pq, (Task){100});
    std::cout << "Priority queue after push:" << std::endl;
    for (int i = 0; i < pq.size; i++){
      std::cout << pq.data.priority << " ";
    }
    std::cout << std::endl;
    return 0;
}


/*堆排序——优化的选择排序*/

#include <iostream>


void heapify(int arr[], int n, int i) {
    /*构建堆*/
    int parent = i, child;
    while ((child = 2 * parent + 1) < n) {
      if (child + 1 < n && arr < arr) child++;
      if (child < n && arr < arr) {
            std::swap(arr, arr);
      }else{
            break;
      }
      parent = child;
    }
}

void heapSort(int arr[], int n) {
    for (int i = n / 2 - 1; i >= 0; i--) heapify(arr, n, i);// 从最后一个非叶子节点开始调整堆
    for (int i = n - 1; i > 0; i--) {
      std::swap(arr, arr);
      heapify(arr, i, 0); // 调整前i个元素为最大堆,第i个之后的元素为已排序的元素
    }
}

int main() {
    int arr[] = { 12, 11, 13, 5, 6, 7 };
    int n = sizeof(arr) / sizeof(arr);

    heapSort(arr, n);

    std::cout << "Sorted array is \n";
    for (int i = 0; i < n; i++) {
      std::cout << arr << " ";
    }
}




页: [1]
查看完整版本: 堆和优先队列