void init_heap(MinHeap *heap,int capacity) { heap->data=(Edge*)malloc(sizeof(Edge)*capacity); heap->size=0; heap->capacity=capacity; } void push_heap(MinHeap *heap,Edge e) { int i; i=++heap->size; while(i>1&&heap->data[i/2].w>e.w) { heap->data[i]
时间: 2024-04-27 11:22:41 浏览: 82
这是一个最小堆(MinHeap)的实现,用于存储边(Edge)并进行堆排序(heap sort)。
函数 init_heap 用于初始化一个最小堆,其中 heap->data 用于存储边,heap->size 表示当前堆的大小,heap->capacity 是堆的容量。
函数 push_heap 用于向最小堆中添加一条边 e,先将边插入到堆的最后一个位置,然后进行堆调整,将边上浮到其正确的位置。
在 while 循环中,每次将 i 指向当前节点的父节点,如果父节点的权值大于要插入的边的权值,就将父节点下沉到当前节点的位置,继续向上比较,直到当前节点的权值小于等于其父节点的权值或者已经到达堆顶。最后将要插入的边插入到 i 指向的位置即可。
这个最小堆的实现可以用于解决最小生成树(Minimum Spanning Tree)问题,例如 Prim 算法和 Kruskal 算法。
相关问题
如何使用C语言实现分治算法解决次序选择问题?给定一个包含n个元素(1 <= k <= n)的已排序线性数组,目标是找到第k小的元素,请提供相应的C代码实现步骤。
在C语言中,我们可以使用分治法(Divide and Conquer)的思想,结合二分查找,来解决次序选择问题。这里有一个经典的算法叫做“最小堆”或“最左堆”,它可以在O(log n)的时间复杂度内找到第k小的元素。
以下是简单的步骤:
1. **分割** (Divide): 首先将整个有序数组视为一个问题,然后将其划分为两半,左边一半和右边一半。
2. **求解** (Conquer): 对每一半递归地执行同样的过程,直到每半只有一个元素(这相当于基础情况,因为单个元素已经是第1小的了)。如果k小于当前一半的大小,那么第k小的元素一定在另一半;否则,在当前一半里。
3. **合并** (Combine): 当遇到k正好等于一半的大小时,我们知道第k小的元素就在当前这个一半的中间位置。为了得到准确的第k小元素,我们将这一半继续调整成一个小顶堆(最小堆),堆顶元素就是我们要找的第k小的元素。
4. **返回结果** (Return): 递归向上合并,当回到原始问题时,就找到了第k小的元素。
下面是对应的C代码实现:
```c
#include <stdio.h>
#include <stdlib.h>
// 定义一个最小堆结构
typedef struct {
int *arr;
int size;
int capacity;
} MinHeap;
// 初始化堆
void minHeapInit(MinHeap *heap, int capacity) {
heap->arr = (int*)malloc(capacity * sizeof(int));
heap->size = 0;
heap->capacity = capacity;
}
// 插入元素到堆
void minHeapInsert(MinHeap *heap, int value) {
if (heap->size == heap->capacity) {
heap->capacity *= 2;
heap->arr = (int*)realloc(heap->arr, heap->capacity * sizeof(int));
}
heap->arr[heap->size] = value;
heap->size++;
siftUp(heap, heap->size - 1);
}
// 调整堆使得根部始终是最小值
void siftUp(MinHeap *heap, int i) {
while (i > 0 && heap->arr[(i - 1) / 2] > heap->arr[i]) {
swap(&heap->arr[i], &heap->arr[(i - 1) / 2]);
i = (i - 1) / 2;
}
}
// 找到第k小元素并返回
int findKthSmallest(MinHeap *heap, int k) {
minHeapInsert(heap, heap->arr[0]); // 将第一个元素插入堆
for (int i = 1; i < k; ++i) {
if (heap->size > 0) {
minHeapInsert(heap, heap->arr[heap->size - 1]); // 保持堆大小不变,插入最大值
siftDown(heap, 0); // 下沉操作,保证堆顶是堆中第i+1小的数
} else {
break; // 如果此时堆为空,则表明k已经超过数组大小
}
}
return heap->arr[0]; // 返回堆顶,即第k小的元素
}
// 清理堆内存
void minHeapDestroy(MinHeap *heap) {
free(heap->arr);
heap->arr = NULL;
heap->size = 0;
heap->capacity = 0;
}
int main() {
int arr[] = {1, 3, 5, 7, 9};
int n = sizeof(arr) / sizeof(arr[0]);
int k = 3;
MinHeap heap;
minHeapInit(&heap, n);
// ... 其他操作 ...
int kth_smallest = findKthSmallest(&heap, k);
printf("The %dth smallest element is: %d\n", k, kth_smallest);
minHeapDestroy(&heap);
return 0;
}
```
在这个例子中,我们首先创建了一个最小堆,然后通过插入和下沉操作找到第k小的元素。注意,由于数组已经排序,实际操作中可以直接遍历数组找到第k小的元素,但这不是分治策略。
利用C语言编写一个完整代码。具体要求为:从键盘任意输入一个带空格由英文字母构成的文本字符串,例如“ilikelearningdatastructurecourse”,首先根据该字符串创建Huffman树,之后进行Huffman编码,然后把该字符串的Huffman编码结果向屏幕输出。能够利用前述的Huffman编码结果对某0-1码流进行解码得到字符串,并作出详细注释
以下是完整代码:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_TREE_HT 100 // 最大树高度
typedef struct MinHeapNode {
char data;
unsigned freq;
struct MinHeapNode *left, *right;
} MinHeapNode;
typedef struct MinHeap {
unsigned size;
unsigned capacity;
MinHeapNode **array;
} MinHeap;
typedef struct HuffmanCode {
char data;
char *code;
} HuffmanCode;
MinHeapNode *newNode(char data, unsigned freq) {
MinHeapNode *node = (MinHeapNode *)malloc(sizeof(MinHeapNode));
node->left = node->right = NULL;
node->data = data;
node->freq = freq;
return node;
}
MinHeap *createMinHeap(unsigned capacity) {
MinHeap *minHeap = (MinHeap *)malloc(sizeof(MinHeap));
minHeap->size = 0;
minHeap->capacity = capacity;
minHeap->array = (MinHeapNode **)malloc(minHeap->capacity * sizeof(MinHeapNode *));
return minHeap;
}
void swapMinHeapNode(MinHeapNode **a, MinHeapNode **b) {
MinHeapNode *t = *a;
*a = *b;
*b = t;
}
void minHeapify(MinHeap *minHeap, int idx) {
int smallest = idx;
int left = 2 * idx + 1;
int right = 2 * idx + 2;
if (left < minHeap->size && minHeap->array[left]->freq < minHeap->array[smallest]->freq)
smallest = left;
if (right < minHeap->size && minHeap->array[right]->freq < minHeap->array[smallest]->freq)
smallest = right;
if (smallest != idx) {
swapMinHeapNode(&minHeap->array[smallest], &minHeap->array[idx]);
minHeapify(minHeap, smallest);
}
}
int isSizeOne(MinHeap *minHeap) {
return (minHeap->size == 1);
}
MinHeapNode *extractMin(MinHeap *minHeap) {
MinHeapNode *temp = minHeap->array[0];
minHeap->array[0] = minHeap->array[minHeap->size - 1];
--minHeap->size;
minHeapify(minHeap, 0);
return temp;
}
void insertMinHeap(MinHeap *minHeap, MinHeapNode *minHeapNode) {
++minHeap->size;
int i = minHeap->size - 1;
while (i && minHeapNode->freq < minHeap->array[(i - 1) / 2]->freq) {
minHeap->array[i] = minHeap->array[(i - 1) / 2];
i = (i - 1) / 2;
}
minHeap->array[i] = minHeapNode;
}
void buildMinHeap(MinHeap *minHeap) {
int n = minHeap->size - 1;
int i;
for (i = (n - 1) / 2; i >= 0; --i)
minHeapify(minHeap, i);
}
void printArr(int arr[], int n) {
int i;
for (i = 0; i < n; ++i)
printf("%d", arr[i]);
printf("\n");
}
int isLeaf(MinHeapNode *root) {
return !(root->left) && !(root->right);
}
MinHeap *createAndBuildMinHeap(char data[], int freq[], int size) {
MinHeap *minHeap = createMinHeap(size);
int i;
for (i = 0; i < size; ++i)
minHeap->array[i] = newNode(data[i], freq[i]);
minHeap->size = size;
buildMinHeap(minHeap);
return minHeap;
}
MinHeapNode *buildHuffmanTree(char data[], int freq[], int size) {
MinHeapNode *left, *right, *top;
MinHeap *minHeap = createAndBuildMinHeap(data, freq, size);
while (!isSizeOne(minHeap)) {
left = extractMin(minHeap);
right = extractMin(minHeap);
top = newNode('$', left->freq + right->freq);
top->left = left;
top->right = right;
insertMinHeap(minHeap, top);
}
return extractMin(minHeap);
}
void printCodes(MinHeapNode *root, int arr[], int top, HuffmanCode huffCodes[]) {
if (root->left) {
arr[top] = 0;
printCodes(root->left, arr, top + 1, huffCodes);
}
if (root->right) {
arr[top] = 1;
printCodes(root->right, arr, top + 1, huffCodes);
}
if (isLeaf(root)) {
int i;
for (i = 0; i < top; ++i) {
char *code = (char *)malloc(sizeof(char) * (top + 1));
code[i] = arr[i] + '0';
code[i + 1] = '\0';
strcat(huffCodes[root->data].code, code);
}
}
}
void HuffmanCodes(char data[], int freq[], int size, HuffmanCode huffCodes[]) {
MinHeapNode *root = buildHuffmanTree(data, freq, size);
int arr[MAX_TREE_HT], top = 0;
printCodes(root, arr, top, huffCodes);
}
void decodeHuffman(MinHeapNode *root, char *code, char *result) {
int i;
MinHeapNode *temp = root;
for (i = 0; code[i] != '\0'; ++i) {
if (code[i] == '0')
temp = temp->left;
else
temp = temp->right;
if (isLeaf(temp)) {
strncat(result, &temp->data, 1);
temp = root;
}
}
}
int main() {
char text[100];
printf("请输入一个带空格由英文字母构成的文本字符串:\n");
fgets(text, sizeof(text), stdin);
text[strcspn(text, "\n")] = '\0'; // 去掉换行符
int len = strlen(text);
int freq[26] = {0};
int i, j;
for (i = 0; i < len; ++i) {
if (text[i] != ' ')
++freq[text[i] - 'a'];
}
char data[26];
for (i = 0, j = 0; i < 26; ++i) {
if (freq[i] != 0) {
data[j] = 'a' + i;
++j;
}
}
data[j] = '\0';
int size = strlen(data);
HuffmanCode huffCodes[26];
for (i = 0; i < size; ++i) {
huffCodes[i].data = data[i];
huffCodes[i].code = (char *)malloc(sizeof(char));
huffCodes[i].code[0] = '\0';
}
HuffmanCodes(data, freq, size, huffCodes);
char huffCode[100] = "";
for (i = 0; i < len; ++i) {
if (text[i] != ' ') {
for (j = 0; j < size; ++j) {
if (text[i] == huffCodes[j].data) {
strcat(huffCode, huffCodes[j].code);
break;
}
}
}
}
printf("该字符串的Huffman编码结果为:%s\n", huffCode);
char result[100] = "";
decodeHuffman(buildHuffmanTree(data, freq, size), huffCode, result);
printf("对该Huffman编码结果进行解码得到的字符串为:%s\n", result);
return 0;
}
```
代码的思路如下:
1. 从键盘输入一个带空格由英文字母构成的文本字符串。
2. 统计文本字符串中每个字母出现的频率。
3. 根据字母出现的频率创建Huffman树。
4. 根据Huffman树进行Huffman编码,得到每个字母的编码。
5. 根据每个字母的编码,将原文本字符串进行编码。
6. 输出编码结果。
7. 对编码结果进行解码,得到原字符串。
代码中使用了Min Heap(最小堆)来构建Huffman树,使用了递归的方式来打印每个字母的编码。解码时,从Huffman树的根节点开始遍历编码,直到找到叶子节点,就将该节点对应的字母加入结果中,并将当前节点重新设置为根节点。
阅读全文