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)
相关推荐
仰泳的熊猫1 天前
题目1099:校门外的树
数据结构·c++·算法·蓝桥杯
求梦8201 天前
【力扣hot100题】反转链表(18)
算法·leetcode·职场和发展
NAGNIP1 天前
机器学习特征工程中的特征选择
算法·面试
ayaya_mana1 天前
VS Code 远程开发:SSH连接与远程资源管理器的配置
linux·ide·windows·vscode·远程资源管理
l1t1 天前
DeepSeek辅助编写的利用位掩码填充唯一候选数方法求解数独SQL
数据库·sql·算法·postgresql
choumin1 天前
在 Debian 上安装并运行 PoCL
linux·编译·安装·pocl
项目題供诗1 天前
C语言基础(二)
c语言·开发语言
Z1Jxxx1 天前
反序数反序数
数据结构·c++·算法
副露のmagic1 天前
更弱智的算法学习 day25
python·学习·算法
求梦8201 天前
【力扣hot100题】移动零(1)
算法·leetcode·职场和发展