首页 > 其他分享 >C语言实现数组堆并解决TopK问题

C语言实现数组堆并解决TopK问题

时间:2024-11-29 23:34:05浏览次数:7  
标签:arr int father C语言 TopK 数组 child array php

还是先定义结构体

typedef int HPDataType;
typedef struct {
    HPDataType* array;
    int size;
    int capacity;
} HP;
void HeapInit(HP* php) {
    assert(php);
    php->array = NULL;
    php->capacity = php->size = 0;
}

首先是它的初始化。

void HeapDestroy(HP* php) {
    assert(php);
    free(php->array);
    php->capacity = php->size = 0;
}

堆的销毁。

void HeapPrint(HP* php) {
    assert(php);
    for (int i = 0; i < php->size; i++) {
        printf("%d  ", php->array[i]);
    }
    printf("\n");
}

打印堆。

bool HeapIsEmpty(HP* php) {
    assert(php);
    return php->size == 0;
}

判断堆是否为空。

void HeapCheckCapacity(HP* php) {
    if (php->capacity == php->size) {
        int newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;
        HPDataType* tmpArray = (HPDataType*)realloc(php->array, sizeof(HPDataType) * newCapacity);
        if (tmpArray == NULL) {  // 检查 realloc
            printf("realloc failed!\n");
            exit(-1);
        }
        php->capacity = newCapacity;
        php->array = tmpArray;
    }
}

检查堆是否需要扩容。如果已满(capacity=size),我们就需要重新设定capacity和为数组分配空间,这里的realloc函数用来为数组重新分配空间。

void Swap(HPDataType* px, HPDataType* py) {
    HPDataType tmp = *px;
    *px = *py;
    *py = tmp;
}

交换函数,下面会用到。

void MinAdjustUp(int* arr, int child) {
    assert(arr);
    int father = (child - 1) / 2;
    while (child > 0) {
        if (arr[child] < arr[father]) {
            Swap(&arr[child], &arr[father]);
            child = father;
            father = (child - 1) / 2;
        }
        else {
            break;
        }
    }
}

小堆向上调整。传入child,跟据其计算出father的值。child>0是为了确保避免调整操作超出数组,这里的child=father和father=(child-1)/2可以让操作继续向上执行。如果无需交换,就直接break跳出此次循环。

void HeapPush(HP* php, HPDataType x) {
    assert(php);
    HeapCheckCapacity(php);
    php->array[php->size] = x;
    php->size++;
    MinAdjustUp(php->array, php->size - 1);
}

新元素入小堆。将新元素先添加到数组末尾,然后调用小堆向上调整操作。

void MinAdjustDown(int* arr, int n, int father) {
    int child = (father * 2) + 1;
    while (child < n) {
        if (child + 1 < n && arr[child + 1] < arr[child])
            child = child + 1;
        if (arr[father] > arr[child]) {
            Swap(&arr[father], &arr[child]);
            father = child;
            child = (father * 2) + 1;
        }
        else {
            break;
        }
    }
}

小堆向下调整操作。传入father,计算出child,这里的child是左孩子。while内第一个if是为了找到左右孩子中最小的,用来与father交换,记得更新father和child的值,以便操作能继续进行。

void HeapPop(HP* php) {
    assert(php);
    assert(!HeapIsEmpty(php));
    Swap(&php->array[0], &php->array[php->size - 1]);
    php->size--;
    MinAdjustDown(php->array, php->size, 0);
}

删除小堆的顶点。先交换堆顶和堆尾数据,然后删除堆尾,再将堆顶元素进行小堆向下调整。

HPDataType HeapTop(HP* php) {
    assert(php);
    assert(!HeapIsEmpty(php));
    return php->array[0];
}

获得堆顶元素。

void printTopK(int* arr, int N, int K) {
    HP hp;
    HeapInit(&hp);
    for (int i = 0; i < K; i++)
        HeapPush(&hp, arr[i]);
    for (int i = K; i < N; i++) {
        if (arr[i] > HeapTop(&hp)) {
            HeapPop(&hp);
            HeapPush(&hp, arr[i]);
        }
    }
    HeapPrint(&hp);
    HeapDestroy(&hp);
}

这个函数可以在N个元素中找到前K个最大元素,即TopK问题。如上,先创建一个小堆,然后将其它N-K个元素与堆头比较,如果大于,就删除堆顶,再将新元素推进堆中,数字越大,下沉越深。

循环结束后打印出的小堆就是前K个最大的元素。

void testPrintTopK() {
    int arr[] = { 51, 334, 87, 150, 25, 65, 66, 34, 72 };
    int N = sizeof(arr) / sizeof(arr[0]);
    int K = 5;

    printf("Original array: ");
    for (int i = 0; i < N; i++) {
        printf("%d  ", arr[i]);
    }
    printf("\n");

    printTopK(arr, N, K);
}

测试函数。用来验证上面方法的正确性。

标签:arr,int,father,C语言,TopK,数组,child,array,php
From: https://blog.csdn.net/2301_80191390/article/details/144146998

相关文章

  • P5015 [NOIP2018 普及组] 标题统计 C语言
    先说思路:跟着题意来就好,其实更多的是考察fgets()函数的基础运用,之后用循环遍历字符串,若是遇到空格和换行符就不计入,反之count++;这里也可以直接用isalnum()直接对输入的字符是否是字母或是数字进行判断。以下是代码实现:#include<stdio.h>#include<ctype.h>intmain(){......
  • MarsCode青训营序章Day1|稀土掘金-1.找单独的数、47.完美偶数计数、3.数组字符格式化
    稀土掘金-1.找单独的数(1.找单独的数)题目分析:n个同学每人持有1张写有数字的卡片,除了一个数字之外,其他每个数字均出现了刚好2次,要求设计时间复杂度为O(n)的算法从cards数组中查找该单独的数。题目重点:已知除单独的数外,其余的都是成对的数,则不存在重复次数超过2的数。需要使时......
  • JavaScript 数组方法详解与实践
    #JavaScript  #前端 在JavaScript中,数组是一个非常强大的数据结构,提供了多种内置方法来处理和操作数据。本文将详细介绍几种常用的数组方法:push(), unshift(), splice(), filter(), find(), forEach(), reverse(), map()。我们将逐一探讨它们的使用方法、测试用例......
  • c语言动态通讯录
    首先我们得明确它的基本功能,信息:1.人的信息:姓名+年龄+性别+地址+电话2.通讯录的可以存放100个人的信息3.功能:1>增加联系人2>删除指定联系人3>查找指定联系人的信息4>修改指定联系人的信息5>显示所有联系人的信息6>排序(姓名,年龄)test.c 测试通讯录contact.c 通讯......
  • 树状数组
    前缀和之树状数组树状数组(FenwickTree)是一种用于高效处理区间查询与修改的重要工具。它可以在(O(logn))的时间复杂度内完成单点更新和前缀区间求和的操作。一、树状数组的基本思想树状数组通过一个辅助数组(c[i])实现,将原数组的信息以一种特殊的方式存储,使得查询和更新都......
  • 【每日一题】209. 长度最小的子数组
    给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其总和大于等于 target 的长度最小的 子数组 [numsl,numsl+1,...,numsr-1,numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。示例1:输入:target=7,nums=[2,3,1,2,4,3]......
  • 力扣每日一题 单调数组对的数目(dp)
     题目困难 动态规划给你一个长度为 n 的 正 整数数组 nums 。如果两个 非负 整数数组 (arr1,arr2) 满足以下条件,我们称它们是 单调 数组对:两个数组的长度都是 n 。arr1 是单调 非递减 的,换句话说 arr1[0]<=arr1[1]<=...<=arr1[n-1] 。arr2......
  • 【每日一题】3251. 单调数组对的数目 II
      给你一个长度为 n 的 正 整数数组 nums 。如果两个 非负 整数数组 (arr1,arr2) 满足以下条件,我们称它们是 单调 数组对:两个数组的长度都是 n 。arr1 是单调 非递减 的,换句话说 arr1[0]<=arr1[1]<=...<=arr1[n-1] 。arr2 是单调 非递增 ......
  • C语言 - 指针,数组
    指针指针入门创建变量intage=10;创建指针,指向变量指针类型*指针变量=&变量int*p=&age;当有了指针之后,就可以通过指针操作他指向的数据了通过指针获取指向的位置的数据,在指针前面加一个*为解引用指针前加*修改,改的是指针指向的位置的值指针的作用:游......
  • SZU实验八数组2【id:362】【15分】D. 矩阵操作(数组)
    题目描述给定一个N阶初始矩阵,现有以下操作TRANSLATE:转置,即将aij变为aji,操作结束后输出矩阵,并将这一新矩阵储存至原二维数组中。ADD:将该矩阵与一矩阵相加得到一新矩阵,操作结束后输出这一新矩阵,并将这一新矩阵储存至原二维数组中。MULTIPLY:与该矩阵与一矩阵相乘得到一......