C语言实现堆的简单操作的示例代码

C语言实现堆的简单操作的示例代码

堆的定义

堆是指通过比较之后使得数组满足大/小根堆性质的一种近似完全二叉树结构。

堆的结构

堆有两种类型,分别为大根堆和小根堆。大根堆指所有父结点都大于等于其子结点,小根堆则相反,所有父结点都小于等于其子结点。

假设i为当前结点,那么其父结点为(i-1)/2,左子结点为(2i+1),右子结点为(2i+2)。

堆支持如下操作:

  1. 将一个元素加入到堆中

  2. 返回堆中最小/大值

  3. 删除堆中最小/大值

堆的实现

要实现一个堆,需要用到下面几个重要的函数:

  • MaxHeapify:将堆的某一个非叶子结点与子结点进行比较,从而得到大根堆。而对于小根堆,则是将其变为小根堆。

  • BuildMaxHeap:建立堆,从无序的数组开始建立一个大根堆/小根堆

  • HeapSort:对无序数组进行排序,由于最大/小值在根结点中,先将根结点(最大/小值)与最后一位进行交换,然后将除最后一位的剩余数组调整为大根堆

  • Insert:插入一个元素,插到堆的尾部,调用_sift_up_ 负责新元素的上移操作

  • DeleteMax:移除最大元素。将堆顶元素及末尾元素交换,移除末尾元素,再调用_sift_down_ 负责新顶点的下移操作。

  • Heapify:将任一数组变成堆。

下面我们通过代码实现堆的基本操作:插入和删除最大值

插入操作

void insert(int arr[], int n, int value){
    arr[n] = value;  // 新元素插在末尾
    int i = n;
    while(i > 0 && arr[(i-1)/2] < arr[i]){  // 如果新元素比父结点大,与父结点交换
        swap(arr[i], arr[(i-1)/2]);
        i = (i-1)/2;
    }
}

在这个函数中,首先将新元素插在末尾,然后使用while循环,循环条件保证了当前结点的父结点存在且其值小于当前结点的值,最后交换两者。这样的操作被称为_sift-up_,因为新元素已经插入到堆中,我们需要将其“上移”以保证堆的性质。

删除最大值

int remove(int arr[], int n){
    // 先将堆顶和堆底交换
    int root_value = arr[0];
    arr[0] = arr[n-1];
    n--;
    // 然后对堆顶执行_sift-down_
    int i = 0;
    while(i < n){
        int max_value = arr[i];
        int max_index = i;
        // 发现左子结点比当前结点大
        if(2*i + 1 < n && arr[2*i + 1] > max_value){
            max_value = arr[2*i + 1];
            max_index = 2*i + 1;
        }
        // 发现右子结点比当前结点大
        if(2*i + 2 < n && arr[2*i + 2] > max_value){
            max_value = arr[2*i + 2];
            max_index = 2*i + 2;
        }
        // 堆的性质被满足,处理结束
        if(max_index == i){
            break;
        }
        swap(arr[max_index], arr[i]);
        i = max_index;
    }
    return root_value;
}

这个函数首先将堆顶(即最大值)与堆底(最右边值)进行交换。接着执行_sift-down_ 操作,将新的根结点下放到其应被放置的位置使得堆的性质被满足。这里需要不断地获取左右结点,并交换以满足堆的性质。这种方式被称为“sift-down”。

示例说明

以大根堆为例,给出以下无序数组:

int arr[] = {10, 20, 15, 40, 50, 30};
int n = sizeof(arr)/sizeof(arr[0]);

我们来分别看看其插入和删除最大值之后的操作:

插入操作

如果在这个堆中插入元素60:

insert(arr, n, 60);

那么堆就变成:

60, 20, 15, 10, 50, 30, 40
删除最大值操作

如果我们先执行一次insert(arr, n, 60)函数,然后再删除其中元素60:

int root_value = remove(arr, n);

那么堆就变成:

50, 20, 15, 10, 40, 30

最大值被返回并从本堆中删除。

总结

通过上述示例,我们可以清楚地看到添加和删除堆元素的操作及其具体实现。同时,我们还可以使用大根堆和小根堆对数组进行排序,以提高算法效率。可以看出,堆是一种相对简单而强大的数据结构。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言实现堆的简单操作的示例代码 - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • win10系统运行帝国时代2提示错误代码0xc0000022的原因及解决方法

    问题描述 当使用win10系统运行帝国时代2游戏时,会提示错误代码0xc0000022,导致游戏无法正常运行。那么这个错误的出现原因是什么?该如何解决呢? 问题原因 错误代码0xc0000022通常是由于系统权限问题引起的,可能是由于以下原因导致: 游戏所在的目录或文件夹没有设置读写权限。 游戏所在的目录或文件夹被防病毒软件或其他安全软件阻止了读取或写入操作…

    C 2023年5月24日
    00
  • C语言中如何进行运算?

    在C语言中,运算是指将一个或多个操作数结合在一起并应用特定的运算符以生成一个结果。C语言中支持多种运算类型,如算术运算、赋值运算、比较运算、逻辑运算等。 算术运算 C语言中的算术运算包括加、减、乘、除、取模等操作。其中,加、减、乘、除分别对应运算符 +、-、*、/,取模使用运算符%。下面是算术运算的示例代码: #include<stdio.h> …

    C 2023年4月27日
    00
  • Python类的继承super相关原理解析

    Python中的类可以通过继承来扩展父类的功能。而在子类中,我们通常需要调用父类中的方法或属性来实现一些特定的功能,这时候就需要用到super()函数来实现。本篇文章将对Python类的继承与super()函数进行详细讲解。 Python类的继承 Python中的类继承是一种重要的面向对象编程思想中的体现,它允许我们在已有的类的基础上创建新的类,同时不破坏原…

    C 2023年5月23日
    00
  • C语言如何建立动态链表问题

    建立动态链表是C语言中常见的数据结构应用之一。以下是如何建立动态链表的完整攻略: 步骤一:定义链表结构 首先需要定义一个链表结构体,包括节点数据和指向下一个节点的指针。 typedef struct Node { int data; struct Node *next; } Node; 步骤二:创建头结点 链表的头结点是链表的入口,不存储数据,只存储链表中第…

    C 2023年5月23日
    00
  • C程序 冒泡排序

    以下是详细讲解“C程序 冒泡排序”的完整使用攻略。 冒泡排序概述 冒泡排序是一种简单的排序算法,它重复地遍历要排序的序列,一次比较两个元素,如果它们的顺序错误就把它们交换过来,直到没有元素需要交换,排序完成。 冒泡排序的时间复杂度为O(n²)。 以下是C语言中实现冒泡排序的代码示例: void bubble_sort(int *arr, int n) { i…

    C 2023年5月9日
    00
  • C#实现JSON解析器MojoUnityJson功能(简单且高效)

    C#实现JSON解析器MojoUnityJson功能(简单且高效) 简介 JSON格式是一种轻量级的数据交换格式,常用于web应用程序之间的数据传输,也广泛应用于移动应用程序的数据交互。MojoUnityJson是一款基于C#的JSON解析器,使用简单且高效。 实现过程 1. 定义数据类型 首先,我们需要定义一些数据类型,方便后续对JSON数据进行解析和处理…

    C 2023年5月23日
    00
  • 联想C4030一体机怎么拆后盖加内存?

    联想C4030一体机拆后盖加内存攻略 确认机器是否需要修改 在进行电脑内存升级操作之前,需要先确认电脑的内存是否需要升级。打开“我的电脑”进入“系统属性”,可以看到当前系统内存的容量,如果内存容量过小,那么可以考虑升级内存。 确认内存条的属性 在购买内存条之前,需要先确认当前电脑内存条的属性,包括品牌、型号、容量和频率等信息。可以通过一些软件来查看,如AID…

    C 2023年5月23日
    00
  • 浅谈html特殊字符 编码css3 content:”我是特殊符号”

    下面是关于”浅谈HTML特殊字符编码CSS3 content”的攻略: HTML特殊字符 在HTML中,有一些字符是有特殊含义的,例如<和>用于表示标签的开始与结束,如果我们想要在HTML中显示这些字符本身,就需要使用特殊字符。 特殊字符使用&和;来表示,其中&为特殊字符的开始标记,;为特殊字符的结束标记。例如,&lt;表…

    C 2023年5月22日
    00
合作推广
合作推广
分享本页
返回顶部