堆排序的插入和删除

2024-08-21 16:44
文章标签 删除 插入 堆排序

本文主要是介绍堆排序的插入和删除,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

插入:

        1.  检查你的顺序表是否还有位置去插入,如果没有需要扩展

        2. 插入到已有序列的后一位置

        3. 和其父节点进行比较,是否满足大根堆/小根堆规则

        4. 不满足则需要交换数值

删除:

        1. 将最后一个元素覆盖将要删除的元素,然后将最后一个元素置空

图1-1输出说明:

        1.  建立大根堆然后排序结果

        2. 插入元素后 结果

        3. 插入元素 调整好新元素位置后 输出结果

        4. 重新排序结果

        5. 删除数据后结果

 

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>/*大根堆:根节点的值大于左右孩子的数值*/
/*
1. 建立大根堆(检查所有的非终端结点 i<=n/2的结点  下标0舍弃不用)
2. 如果根节点不满足大根堆 那么将根节点与他最大的孩子结点交换 小元素不断下坠
3. 然后交换根节点和最后一个元素  根节点是最大的 最后一个元素是最小的
*/typedef struct {int* e;//存储堆数据int len;//堆的长度  元素个数int mlen;//堆的最大长度
}Heap;void InitHeap(Heap *hp,int n) {(*hp).e = (int*)malloc(sizeof(int) * (n + 1)); //0号位置不使用(*hp).len = 0;(*hp).mlen = n;
}//将数据填入数组中
void AddData(Heap hp, int d[], int n) {for (int i = 1; i <= n; i++) {hp.e[i] = d[i - 1];}
}
//将以k为根结点的树调整为大根堆
void HeapAdjust(Heap hp, int k, int n) {hp.e[0] = hp.e[k];   //临时存储该根节点的数据//沿着数值较大的子节点向下筛选for (int i = 2 * k; i <= n; i *= 2) {//左孩子结点if (i < n && hp.e[i] < hp.e[i + 1])i++;//右孩子大if (hp.e[0] > hp.e[i])  break;else {hp.e[k] = hp.e[i];k = i;}}hp.e[k] = hp.e[0];
}
void HeapAdjustLittle(Heap hp, int k, int n) {hp.e[0] = hp.e[k];   //临时存储该根节点的数据//沿着数值较大的子节点向下筛选for (int i = 2 * k; i <= n; i *= 2) {//左孩子结点if (i < n && hp.e[i] > hp.e[i + 1])i++;//右孩子小if (hp.e[0] < hp.e[i])  break;else {hp.e[k] = hp.e[i];k = i;}}hp.e[k] = hp.e[0];
}
//建立大根堆
void BuildBigRootHeap(Heap hp, int n) {for (int i = n / 2; i >= 1; i--) {HeapAdjust(hp, i, n);}}
void Print(Heap hp, int n) {for (int i = 1; i <= n; i++) {printf("%d   ", hp.e[i]);}printf("\n");
}//堆排序:每一趟将堆顶元素加入到有序子序列与待排序序列的最后一个元素交换
//交换以后,len长度数值-1  然后在将待排序树调整为大根堆  小元素下坠的过程 然后每一趟选出一个最大的数值
void HeapSort(Heap hp, int n) {for (int i = n; i >= 1; i--) {int tmp = hp.e[i];hp.e[i] = hp.e[1];hp.e[1] = tmp;//交换最后一个元素和堆顶元素HeapAdjust(hp, 1, i - 1);}
}
//插入元素//1. 扩展空间
/*void ExpandSpase(Heap *hp,int n) {int* p = hp->e;hp->e = (int*)realloc(hp->e,sizeof(int)*(hp->mlen + n));hp->mlen += n;free(p);
}*/
void ExpandSpase(Heap* hp, int n) {hp->e = (int*)realloc(hp->e, sizeof(int) * (hp->mlen + n + 1));hp->mlen += n; // 更新最大长度
}
void swap(int *a,int *b) {int tmp = *a;*a = *b;*b = tmp;
}
/*
注意点:
1. 此时堆已经是有序的了,所以已经由无序大根堆变为了有序小根堆
2. 所以在判断是否交换数据的时候,判断条件是 孩子节点是否大于父亲结点 如果是 那么不交换  否则交换*/
void InsertElement(Heap *hp,int value) {if (hp->len == hp->mlen)ExpandSpase(hp,1);//扩展一个空间hp->len += 1;hp->e[hp->len] = value;printf("插入元素但未调整:\n");Print(*hp, hp->len);hp->e[0] = hp->e[hp->len]; //使用数组下标为0的暂时存储新元素 new element 然后开始和父亲结点进行对比/交换int k = hp->len;//暂时存储孩子结点for (int i = k / 2; i >= 1;i/=2) {if (hp->e[i] < hp->e[k]) break;//孩子结点是否大于父亲  是就不交换 仍然满足小根堆swap(&hp->e[k],&hp->e[i]);k = i;//需要检查的结点(new point)向上移动}printf("调整后:\n");Print(*hp, hp->len);printf("重新排序:\n");
}
//删除:删除就是将最后一个元素覆盖要删除的点,然后数组长度-1  如果删除最后一个结点,那么直接-1即可
//然后采用元素下坠的办法进行调整(大元素下坠)
void DeleteElement(Heap *hp,int i) {//i表示删除第几个元素hp->e[i] = hp->e[hp->len];hp->len--;HeapAdjustLittle(*hp,i,hp->len);printf("删除后:\n");Print(*hp,hp->len);
}
int main() {int data[] = { 53,17,78,9,45,65,87,32 };//数据元素int n = 8;Heap hp;InitHeap(&hp,n);AddData(hp,data,n);hp.len = n;BuildBigRootHeap(hp,n);HeapSort(hp,n);Print(hp, n);//插入元素InsertElement(&hp,1);//重新排序  每次重新排序都要基于大根堆BuildBigRootHeap(hp,hp.len);HeapSort(hp,hp.len);Print(hp,hp.len);//删除1元素DeleteElement(&hp,1);free(hp.e);return 0;
}

这篇关于堆排序的插入和删除的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1093712

相关文章

使用Python删除Excel中的行列和单元格示例详解

《使用Python删除Excel中的行列和单元格示例详解》在处理Excel数据时,删除不需要的行、列或单元格是一项常见且必要的操作,本文将使用Python脚本实现对Excel表格的高效自动化处理,感兴... 目录开发环境准备使用 python 删除 Excphpel 表格中的行删除特定行删除空白行删除含指定

Linux下删除乱码文件和目录的实现方式

《Linux下删除乱码文件和目录的实现方式》:本文主要介绍Linux下删除乱码文件和目录的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux下删除乱码文件和目录方法1方法2总结Linux下删除乱码文件和目录方法1使用ls -i命令找到文件或目录

Mysql实现范围分区表(新增、删除、重组、查看)

《Mysql实现范围分区表(新增、删除、重组、查看)》MySQL分区表的四种类型(范围、哈希、列表、键值),主要介绍了范围分区的创建、查询、添加、删除及重组织操作,具有一定的参考价值,感兴趣的可以了解... 目录一、mysql分区表分类二、范围分区(Range Partitioning1、新建分区表:2、分

MySQL 删除数据详解(最新整理)

《MySQL删除数据详解(最新整理)》:本文主要介绍MySQL删除数据的相关知识,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录一、前言二、mysql 中的三种删除方式1.DELETE语句✅ 基本语法: 示例:2.TRUNCATE语句✅ 基本语

一文详解Git中分支本地和远程删除的方法

《一文详解Git中分支本地和远程删除的方法》在使用Git进行版本控制的过程中,我们会创建多个分支来进行不同功能的开发,这就容易涉及到如何正确地删除本地分支和远程分支,下面我们就来看看相关的实现方法吧... 目录技术背景实现步骤删除本地分支删除远程www.chinasem.cn分支同步删除信息到其他机器示例步骤

python删除xml中的w:ascii属性的步骤

《python删除xml中的w:ascii属性的步骤》使用xml.etree.ElementTree删除WordXML中w:ascii属性,需注册命名空间并定位rFonts元素,通过del操作删除属... 可以使用python的XML.etree.ElementTree模块通过以下步骤删除XML中的w:as

Navicat数据表的数据添加,删除及使用sql完成数据的添加过程

《Navicat数据表的数据添加,删除及使用sql完成数据的添加过程》:本文主要介绍Navicat数据表的数据添加,删除及使用sql完成数据的添加过程,具有很好的参考价值,希望对大家有所帮助,如有... 目录Navicat数据表数据添加,删除及使用sql完成数据添加选中操作的表则出现如下界面,查看左下角从左

如何在Mac上彻底删除Edge账户? 手动卸载Edge浏览器并清理残留文件技巧

《如何在Mac上彻底删除Edge账户?手动卸载Edge浏览器并清理残留文件技巧》Mac上的Edge账户里存了不少网站密码和个人信息,结果同事一不小心打开了,简直尴尬到爆炸,想要卸载edge浏览器并清... 如果你遇到 Microsoft Edge 浏览器运行迟缓、频繁崩溃或网页加载异常等问题,可以尝试多种方

Java实现删除文件中的指定内容

《Java实现删除文件中的指定内容》在日常开发中,经常需要对文本文件进行批量处理,其中,删除文件中指定内容是最常见的需求之一,下面我们就来看看如何使用java实现删除文件中的指定内容吧... 目录1. 项目背景详细介绍2. 项目需求详细介绍2.1 功能需求2.2 非功能需求3. 相关技术详细介绍3.1 Ja

Redis过期删除机制与内存淘汰策略的解析指南

《Redis过期删除机制与内存淘汰策略的解析指南》在使用Redis构建缓存系统时,很多开发者只设置了EXPIRE但却忽略了背后Redis的过期删除机制与内存淘汰策略,下面小编就来和大家详细介绍一下... 目录1、简述2、Redis http://www.chinasem.cn的过期删除策略(Key Expir