首页 > 其他分享 >堆排序的插入和删除

堆排序的插入和删除

时间:2024-08-21 15:57:00浏览次数:11  
标签:删除 int hp 元素 堆排序 len 插入 Heap void

插入:

        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;
}

标签:删除,int,hp,元素,堆排序,len,插入,Heap,void
From: https://blog.csdn.net/weixin_62858623/article/details/141392620

相关文章

  • AVL树、2-3-4树、红黑树节点增加删除原理(详细说明)
    AVL树与红黑树引入:BST(二叉查找树)在插入的时候会导致倾斜,不同的插入顺序会导致树的高度不一样,树的高度直接影响到树的查找效率,最坏的情况就是所有节点就在一条斜线上,导致树的高度为N。平衡二叉树(BalancedBST)在插入和删除的时候,会通过旋转将高度保持在Logn。删除节点:   ......
  • el-upload在定义file插槽时删除图片(包括隐藏上传框)
    1.上传框隐藏效果图(限制上传两张图片,上传两张图片后隐藏上传框) <template><div><el-form><el-uploadref="uploadPicture"action="#"list-type="picture-card"......
  • 删除字符串中的所有相邻重复项(1047)
    题目描述给出由小写字母组成的字符串S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。在S上反复执行重复项删除操作,直到无法继续删除。在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。解题思路这里我们还是使用栈这个数据结构,我们还是遍历当前字符串,......
  • ORA-01940 无法删除当前连接的用户
    ---------------------------------------------------------------------------bayaim----2024年8月20日15:37:53------------------------------------------------------------------------问题背景:想删除用户下所有的对象1、问题现象:执行命令,删除用户:dropuser......
  • 如何删除数据库下的所有表(mysql)
    要在MySQL中删除数据库下的所有表,你有两个主要选项:一个是删除整个数据库然后重新创建它,另一个是查询所有表的名称并逐一删除它们。下面是这两种方法的步骤:方法1:删除并重新创建数据库这种方法是最简单和最快的,但请注意,它会删除整个数据库,包括其中的所有表、视图、存储过程等。......
  • Java实现冒泡排序和插入排序算法
    冒泡排序算法步骤1、比较相邻的元素,如果第一个比第二个大,就交换它们两个;2、对每一对相邻元素作同样的比价,从开始第一对到结尾的最后一对,这样在最后的元素就是最大的数;3、针对所有的元素重复以上的步骤,除了数组最后已经排好序的数组;4、重复步骤1~3,直到排序完成。代码实现pac......
  • 批量创建/删除用户
    #!/bin/bashread-p"请输入你想创建用户的前缀:"prefix[-z$prefix]&&echo"必须输入前缀"&&exit #控制前缀不能为空[[!$prefix=~^[a-Z]+$]]&&echo"请输入正确的前缀"&&exit #控制前缀为字母read-p"请输入你想创建用户的个数:"......
  • C#上传excel,解析主从表,1W数据快速插入数据库,5s完成
    参考文章netcore天马行空系列-各大数据库快速批量插入数据方法汇总ExcelMapperController核心代码[HttpPost]publicasyncTask<IActionResult>ImportToDoItems(IFormFilefile){if(file==null||file.Length==0){returnBadRequest("Fileis......
  • VisualStudio 产生的.sdf和.ipch文件删除、不生成
    前言全局说明VisualStudio产生的.sdf和.ipch文件删除、不生成一、说明环境:Windows7旗舰版VisualStudio2013二、原因某天,打算给vs2013的一个工程,打包备份,打包后,发现压缩包有90MB,看到数字确实很惊讶。因为这个工程就是画了几个按钮的小功能,怎么会这么大。......
  • Qt/C++地图标注点的添加删除移动旋转/指定不同图标和动图/拿到单击信号
    一、前言说明标注点在地图开发中是最常见的应用场景之一,比如在地图上需要显示设备的位置,基本上都是添加标注点,指定图片和尺寸已经经纬度坐标位置。这个功能在每种地图内核中都提供的,这个并没有任何难点,在这个功能点上最大难题或者说是设计细节就是,标注点该如何对齐,比如水滴形状的......