icoding数据结构——数组合并(详细注释)

排序单元前面四道题都是堆,暗示还不够明显吗👀

代码前面除了 heap_insert_value(堆元素插入函数)都是把前面四道题所编写的函数复制过来直接用的

对于 heap_insert_value 函数,需要改造一下,使其也能插入的信息完整多了otherInfo(怪不得 MinHeapNode 里会多了 otherinfo 原来都是有用的太贴心了😭),用 otherinfo 里的 i 和 j 来分别表示【元素所在数组的索引】和【元素在数组中的索引】

思路:

先将每个数组的第一个入堆;输出最小元素的后,将其对应的数组中的下一 个元素入堆,重复即可。

题目:

假设有 n 个长度为 k 的已排好序(升序)的数组,请设计数据结构和算法,将这 n 个数组合并到一个数组,且各元素按升序排列。即实现函数:

 void merge_arrays(const int* arr, int n, int k, int* output);

其中 arr 为按行优先保存的 n 个长度都为 k 的数组,output 为合并后的按升序排列的数组,大小为 n×k。

时间要求(评分规则),当 n > k 时:

  • 满分:时间复杂度不超过 O(n×k×log(n))
  • 75分:时间复杂度不超过 O(n×k×log(n)×k)
  • 59分:其它,如:时间复杂度为 O(n2×k2) 时。

代码:

#include<stdio.h>
#include<stdlib.h>

typedef struct _otherInfo
{
    int i;
    int j;
}OtherInfo;

typedef struct _minHeapNode
{
    int value;
    OtherInfo otherInfo;
}MinHeapNode, * PMinHeapNode;

typedef struct _minPQ {
    PMinHeapNode heap_array; // 指向堆元素数组
    int heap_size; // 当前堆中的元素个数
    int capacity;  //堆数组的大小
}MinHeap, * PMinHeap;

// 返回堆元素数组下标为 i 的结点的父结点下标
int parent(int i) {
    i++;// 注意是数组下标 +1才是完全二叉树的顺序编号
    return i / 2 - 1;// 注意返回也是数组下标 所以要-1    
}

// 返回堆元素数组下标为 i 的结点的左子结点下标
int left(int i) {
    i++;
    return i * 2 - 1;

}

// 返回堆元素数组下标为 i 的结点的右子结点下标
int right(int i) {
    i++;
    return i * 2 + 1 - 1;
}

// 交换两个堆元素的值
void swap_node(MinHeapNode* x, MinHeapNode* y) {
    MinHeapNode temp = *x; // 通过解引用获取指针指向的实际数据
    *x = *y; // 将指针y指向的数据赋值给指针x指向的位置
    *y = temp; // 将保存在temp中的数据赋值给指针y指向的位置
}

// 堆初始化
void init_min_heap(PMinHeap pq, int capacity) {
    pq->capacity = capacity;
    pq->heap_size = 0;
    pq->heap_array = (PMinHeapNode)malloc(capacity * sizeof(MinHeapNode));
}

// 堆元素插入
bool heap_insert_value(PMinHeap pq, int value, int k, int j) {
    if (pq->heap_size == pq->capacity) {
        // 堆已满,无法插入元素
        return false;
    }

    // 创建新的堆节点
    PMinHeapNode newNode = (PMinHeapNode)malloc(sizeof(MinHeapNode));
    if (newNode == NULL) {
        // 内存分配失败
        return false;
    }

    // 将元素插入到堆的最后一个位置
    int i = pq->heap_size;
    pq->heap_array[i].value = value;
    pq->heap_array[i].otherInfo.i = k;
    pq->heap_array[i].otherInfo.j = j;

    // 更新堆大小
    pq->heap_size++;

    // 从插入位置开始向上调整堆,以维持最小堆的性质
    while (i != 0 && pq->heap_array[parent(i)].value > pq->heap_array[i].value) {
        swap_node(&pq->heap_array[i], &pq->heap_array[parent(i)]);
        i = parent(i);
    }

    return true;
}

// 堆化
void min_heapify(PMinHeap pq, int k) {
    int smallest = k;              // 当前节点标记为最小值

    while (true) {
        int l = left(k);           // 当前节点的左子节点索引
        int r = right(k);          // 当前节点的右子节点索引

        // 比较左子节点与当前节点的值,更新最小值的索引
        if (l < pq->heap_size && pq->heap_array[l].value < pq->heap_array[smallest].value) {
            smallest = l;
        }

        // 比较右子节点与当前节点的值,更新最小值的索引
        if (r < pq->heap_size && pq->heap_array[r].value < pq->heap_array[smallest].value) {
            smallest = r;
        }

        // 如果最小值不是当前节点,则进行交换,并更新当前节点索引
        if (smallest != k) {
            swap_node(&pq->heap_array[k], &pq->heap_array[smallest]);
            k = smallest;
        }
        else {
            break;    // 当前节点已经是最小堆,退出循环
        }
    }
}

// 提取堆中的最小元素
int extractMin(MinHeap* heap) {
    int minElement = heap->heap_array[0].value;
    heap->heap_array[0] = heap->heap_array[heap->heap_size - 1];
    heap->heap_size--;
    min_heapify(heap, 0);
    return minElement;
}

void merge_arrays(const int* arr, int n, int k, int* output) {
    // 创建最小堆
    MinHeap* Heap = (MinHeap*)malloc(sizeof(MinHeap));   
    init_min_heap(Heap, n);

    // 将每个数组的第一个元素插入堆中
    for (int i = 0; i < n; i++) {
        // 改造了一下insert函数,使其也能插入的信息完整(多了otherInfo)
        heap_insert_value(Heap, arr[i * k], i, 0);
        // Heap->heap_array[i].otherInfo.i ————所在数组的索引
        // Heap->heap_array[i].otherInfo.j ————元素在数组中的索引
    }

    // 依次从堆中取出最小元素,并将下一个元素插入堆中
    for (int i = 0; i < n * k; i++) {
        // 获取最小元素所在数组的索引和元素在数组中的索引
        int arrIndex = Heap->heap_array[0].otherInfo.i;
        int elemIndex = Heap->heap_array[0].otherInfo.j;

        // 取出堆中的最小元素
        output[i] = extractMin(Heap);

        // 如果当前数组还有元素,将下一个元素插入堆中
        if (elemIndex < k - 1) {
            int value = arr[arrIndex * k + elemIndex + 1];
            heap_insert_value(Heap, value, arrIndex, elemIndex + 1);
        }
    }

    // 记得用完堆需要free
    free(Heap->heap_array);
    free(Heap);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值