Linux环境下的C语言编程(四十二)

一、优先队列概念

优先队列 是一种特殊的队列,元素出队顺序不是FIFO,而是按照优先级

  • 每次出队的是优先级最高(或最低)的元素

二、两种实现方式对比

特性 使用数组/链表(朴素实现) 使用堆(推荐实现)
入队时间复杂度 O(1) O(log n)
出队(获取最高优先级)时间复杂度 O(n) O(log n)
查找最高优先级 O(n) O(1)

三、数组实现

1. 数组无序实现

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

#define MAX_SIZE 100

typedef struct {
    int data[MAX_SIZE];
    int size;
} PriorityQueueArray;

// 初始化
void initPriorityQueueArray(PriorityQueueArray* pq) {
    pq->size = 0;
}

// 入队 O(1) - 直接添加到尾部
void enqueueArray(PriorityQueueArray* pq, int value) {
    if (pq->size >= MAX_SIZE) {
        printf("队列已满!\n");
        return;
    }
    pq->data[pq->size++] = value;
}

// 出队 O(n) - 需要遍历找到最大值
int dequeueArray(PriorityQueueArray* pq) {
    if (pq->size == 0) {
        printf("队列为空!\n");
        return INT_MIN;
    }
    
    // 找到最大值的索引
    int maxIndex = 0;
    for (int i = 1; i < pq->size; i++) {
        if (pq->data[i] > pq->data[maxIndex]) {
            maxIndex = i;
        }
    }
    
    // 保存最大值
    int maxValue = pq->data[maxIndex];
    
    // 用最后一个元素填补空缺
    pq->data[maxIndex] = pq->data[pq->size - 1];
    pq->size--;
    
    return maxValue;
}

// 查看最高优先级 O(n)
int peekArray(PriorityQueueArray* pq) {
    if (pq->size == 0) return INT_MIN;
    
    int maxValue = pq->data[0];
    for (int i = 1; i < pq->size; i++) {
        if (pq->data[i] > maxValue) {
            maxValue = pq->data[i];
        }
    }
    return maxValue;
}
2. 数组有序

四、堆实现

是一种特殊的完全二叉树,满足:

  • 最大堆:父节点 ≥ 子节点

  • 最小堆:父节点 ≤ 子节点

1. 最大堆实现优先队列

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

#define MAX_HEAP_SIZE 100

typedef struct {
    int data[MAX_HEAP_SIZE];
    int size;
} MaxHeap;

// 辅助函数:交换两个元素
void swap(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

// 初始化堆
void initMaxHeap(MaxHeap* heap) {
    heap->size = 0;
}

// 获取父节点索引
int parent(int i) {
    return (i - 1) / 2;
}

// 获取左孩子索引
int leftChild(int i) {
    return 2 * i + 1;
}

// 获取右孩子索引
int rightChild(int i) {
    return 2 * i + 2;
}

// 上浮操作(维护堆性质)O(log n)
void heapifyUp(MaxHeap* heap, int index) {
    while (index > 0 && heap->data[parent(index)] < heap->data[index]) {
        swap(&heap->data[parent(index)], &heap->data[index]);
        index = parent(index);
    }
}

// 下沉操作(维护堆性质)O(log n)
void heapifyDown(MaxHeap* heap, int index) {
    int maxIndex = index;
    int left = leftChild(index);
    int right = rightChild(index);
    
    // 找到当前节点、左孩子、右孩子中的最大值
    if (left < heap->size && heap->data[left] > heap->data[maxIndex]) {
        maxIndex = left;
    }
    if (right < heap->size && heap->data[right] > heap->data[maxIndex]) {
        maxIndex = right;
    }
    
    // 如果当前节点不是最大值,交换并继续下沉
    if (index != maxIndex) {
        swap(&heap->data[index], &heap->data[maxIndex]);
        heapifyDown(heap, maxIndex);
    }
}

// 入队操作 O(log n)
void heapEnqueue(MaxHeap* heap, int value) {
    if (heap->size >= MAX_HEAP_SIZE) {
        printf("堆已满!\n");
        return;
    }
    
    // 1. 将新元素放到末尾
    heap->data[heap->size] = value;
    heap->size++;
    
    // 2. 上浮调整
    heapifyUp(heap, heap->size - 1);
}

// 出队操作 O(log n)
int heapDequeue(MaxHeap* heap) {
    if (heap->size == 0) {
        printf("堆为空!\n");
        return INT_MIN;
    }
    
    // 1. 保存堆顶(最大值)
    int maxValue = heap->data[0];
    
    // 2. 用最后一个元素替换堆顶
    heap->data[0] = heap->data[heap->size - 1];
    heap->size--;
    
    // 3. 下沉调整
    heapifyDown(heap, 0);
    
    return maxValue;
}

// 查看堆顶元素 O(1)
int heapPeek(MaxHeap* heap) {
    if (heap->size == 0) return INT_MIN;
    return heap->data[0];
}

// 构建堆 O(n) - 弗洛伊德建堆法
void buildHeap(MaxHeap* heap, int arr[], int n) {
    // 复制数据
    for (int i = 0; i < n; i++) {
        heap->data[i] = arr[i];
    }
    heap->size = n;
    
    // 从最后一个非叶子节点开始下沉
    for (int i = n / 2 - 1; i >= 0; i--) {
        heapifyDown(heap, i);
    }
}

// 打印堆(树状结构)
void printHeapTree(MaxHeap* heap, int index, int level) {
    if (index >= heap->size) return;
    
    // 先打印右子树
    printHeapTree(heap, rightChild(index), level + 1);
    
    // 打印当前节点
    for (int i = 0; i < level; i++) printf("    ");
    printf("%d\n", heap->data[index]);
    
    // 打印左子树
    printHeapTree(heap, leftChild(index), level + 1);
}

2. 最小堆实现

复制代码
typedef struct {
    int data[MAX_HEAP_SIZE];
    int size;
} MinHeap;

// 最小堆的上浮操作
void minHeapifyUp(MinHeap* heap, int index) {
    while (index > 0 && heap->data[parent(index)] > heap->data[index]) {
        swap(&heap->data[parent(index)], &heap->data[index]);
        index = parent(index);
    }
}

// 最小堆的下沉操作
void minHeapifyDown(MinHeap* heap, int index) {
    int minIndex = index;
    int left = leftChild(index);
    int right = rightChild(index);
    
    if (left < heap->size && heap->data[left] < heap->data[minIndex]) {
        minIndex = left;
    }
    if (right < heap->size && heap->data[right] < heap->data[minIndex]) {
        minIndex = right;
    }
    
    if (index != minIndex) {
        swap(&heap->data[index], &heap->data[minIndex]);
        minHeapifyDown(heap, minIndex);
    }
}

五、时间复杂度对比分析

各种实现的时间复杂度:

操作 无序数组/链表 有序数组
插入(入队) O(1) O(n) O(log n)
删除最大(出队) O(n) O(1) O(log n)
获取最大(查看) O(n) O(1) O(1)
构建 O(1) O(n log n) O(n)
相关推荐
Trouvaille ~2 小时前
【Linux】进程调度与环境变量:Linux内核的智慧
linux·运维·服务器·操作系统·进程·环境变量·调度算法
HalvmånEver2 小时前
Linux : 基础IO(三)
linux·运维·算法
oushaojun22 小时前
linux中backtrace实战
linux·运维·算法·backtrace
soft20015252 小时前
MySQL 8.0.39 Rocky Linux 一键安装脚本(完整可直接运行)
linux·mysql·adb
Nerd Nirvana2 小时前
WSL——Windows Subsystem for Linux流程一览
linux·运维·服务器·windows·嵌入式·wsl·wsl2
埃伊蟹黄面2 小时前
模拟算法思想
c++·算法·leetcode
副露のmagic2 小时前
更弱智的算法学习day 10
python·学习·算法
逸风尊者3 小时前
开发可掌握的知识:uber H3网格
后端·算法
jianfeng_zhu3 小时前
不带头节点的循环双链表
c语言