首页 > 其他分享 >堆结构和堆排序

堆结构和堆排序

时间:2024-10-19 17:47:13浏览次数:7  
标签:int 堆排序 heapsize heap left maxchild 节点 结构

  小伙伴们大家晚上好,今天又是双更的一天。现在为大家带来堆的讲解。

1.完全二叉树以及堆的含义

  首先大家应该明白什么是堆:堆是一种特殊的完全二叉树,又可以分为最大堆和最小堆。我首先展示什么是完全二叉树(以两张图作为例子):

  

  这张图片就展示了完全二叉树。

 

  这张图片就不是完全二叉树。

  那该如何区分呢?教大家一个简单的方法 :从第一层开始,从左往右,看结点是否只有右子树而没有左子树,只要有一个结点符合就不是完全二叉树,若所有结点均不符合,则是完全二叉树。

  最大堆:父节点比其子节点均大的完全二叉树

  最小堆:父节点比其子节点均小的完全二叉树

  这种性质能让我们很好的用数组模拟树结构,数组下标从1开始,那一个节点i的父节点就是i/2,其子节点就是2*i和2*i+1,(可能不存在子节点的某些)大家可以对照上图试验。

  下面我们以最大堆为例展示代码。

2.最大堆的逐个插入

2.1问题分析

  当插入第一个节点时,肯定是最大堆。当插入第二个元素时,只要检查其与其父节点的大小关系,当大于父节点则交换,否则无需交换。同理其它元素,一直交换到其比父节点小或已经位于树根(i==1)。别忘了heapsize++。

2.2代码展示

void heapinsert(int *heap,int x){
	heap[++heapsize]=x;//下标从1开始记录 
	int i=heapsize;
	while(i>1&&heap[i/2]<heap[i]){
		swap(heap[i],heap[i/2]); 
		i=i/2;
	}
}

  其中heapsize为最大堆节点个数。

3.最大堆的删除 

3.1问题分析

  当我们构建好了最大堆时,要想进行删除,则将堆顶删除,同时将heapsize--,并将heapsize位置节点放置堆顶,开始往下和其子节点比较,如果比其子节点最大值小,则交换。否则无需操作。直到其比子节点的最大值大或者其没有子节点。

3.2代码展示

int heapdelete(int *heap){
	int x=heap[1];
	int i=1,maxchild;
	heap[i]=heap[heapsize--];
	int left=i*2;
	while(left<=heapsize){
		if(left+1<=heapsize&&heap[left]<heap[left+1]){
			maxchild=left+1;
		}
		else{
			maxchild=left;
		}
		if(heap[i]<heap[maxchild]){
			swap(heap[i],heap[maxchild]);
			i=maxchild;
			left=i*2;
		}
		else{
			break;
		}
	}
	return x;
}

  要注意右子树是否存在!!否则会越界。

4.最大堆某个节点的修改

 4.1问题分析

  要想修改某个节点的值并仍然维持最大堆,就要判断原值和新值的大小关系。若新值大,则其可能向上走(逐个插入的上沿操作)。若新值小,则其可能向下走(删除操作的下顺操作)。

4.2代码展示

void heapchange(int *heap,int i,int x){
	if(heap[i]<x){
		heap[i]=x;
		while(i>1&&heap[i]>heap[i/2]){
			swap(heap[i],heap[i/2]);
			i=i/2;
		}
	}
	if(heap[i]>x){
		heap[i]=x;
		int left=i*2,maxchild;
		while(left<=heapsize){
			if(left+1<=heapsize&&heap[left+1]>heap[left]){
				maxchild=left+1;
			}
			else{
				maxchild=left;
			}
			if(heap[maxchild]>heap[i]){
				swap(heap[maxchild],heap[i]);
				i=maxchild;
				left=2*i;
			}
		}
	}
}

5.最大堆一次性构建

5.1问题分析

  如果已经存在一颗完全二叉树,要想将其构造成最大堆,则将每个节点进行下沿操作即可(从节点下标最大处开始)。

5.2代码展示

void heapify(int *heap,int i){
	int left=2*i,maxchild;
	while(left<=heapsize){
		if(left+1<=heapsize&&heap[left]<heap[left+1]){
			maxchild=left+1;
		}
		else{
			maxchild=left;
		}
		if(heap[i]<heap[maxchild]){
			swap(heap[i],heap[maxchild]);
			i=maxchild;
			left=i*2;
		}
		else{
			break;
		}
	}
}
//主函数部分
    heapsize=5;
    for(int i=heapsize;i>=1;i--){
    	heapify(heap,i);
    }

  i代表第i个位置。

6.堆排序 

6.1问题分析

  如果只是考虑简单的话,一直进行delete操作取出其堆顶元素存入数组,最后将新数组逆序输出即可。但会引进额外的空间复杂度。因此我们更希望在原数组中操作。我们每次将堆顶和堆尾元素交换,heapsize--,再调用heapify(heap,1),这样堆的最大值就会被我们踢出堆,并且除去后仍然为堆,重复操作直至heapsize==0。最后将数组顺序输出即可。

6.2代码展示

void heapsort(int *heap){
	swap(heap[1],heap[heapsize--]);
	while(heapsize>0){
		heapify(heap,1);
		swap(heap[1],heap[heapsize--]);
	}
	
}

7.总代码(+测试) 

#include<iostream>
using namespace std;
int heapsize=0;
//最大堆 
//N*logN
void heapinsert(int *heap,int x){
	heap[++heapsize]=x;//下标从1开始记录 
	int i=heapsize;
	while(i>1&&heap[i/2]<heap[i]){
		swap(heap[i],heap[i/2]); 
		i=i/2;
	}
}
//N*logN
int heapdelete(int *heap){
	int x=heap[1];
	int i=1,maxchild;
	heap[i]=heap[heapsize--];
	int left=i*2;
	while(left<=heapsize){
		if(left+1<=heapsize&&heap[left]<heap[left+1]){
			maxchild=left+1;
		}
		else{
			maxchild=left;
		}
		if(heap[i]<heap[maxchild]){
			swap(heap[i],heap[maxchild]);
			i=maxchild;
			left=i*2;
		}
		else{
			break;
		}
	}
	return x;
}
void heapchange(int *heap,int i,int x){
	if(heap[i]<x){
		heap[i]=x;
		while(i>1&&heap[i]>heap[i/2]){
			swap(heap[i],heap[i/2]);
			i=i/2;
		}
	}
	if(heap[i]>x){
		heap[i]=x;
		int left=i*2,maxchild;
		while(left<=heapsize){
			if(left+1<=heapsize&&heap[left+1]>heap[left]){
				maxchild=left+1;
			}
			else{
				maxchild=left;
			}
			if(heap[maxchild]>heap[i]){
				swap(heap[maxchild],heap[i]);
				i=maxchild;
				left=2*i;
			}
		}
	}
}
//将数组一次性构成最大堆 
//每个节点位置向下遍历    N
void heapify(int *heap,int i){
	int left=2*i,maxchild;
	while(left<=heapsize){
		if(left+1<=heapsize&&heap[left]<heap[left+1]){
			maxchild=left+1;
		}
		else{
			maxchild=left;
		}
		if(heap[i]<heap[maxchild]){
			swap(heap[i],heap[maxchild]);
			i=maxchild;
			left=i*2;
		}
		else{
			break;
		}
	}
}
//堆排序 n*logn
void heapsort(int *heap){
	swap(heap[1],heap[heapsize--]);
	while(heapsize>0){
		heapify(heap,1);
		swap(heap[1],heap[heapsize--]);
	}
	
}
int main(){
	int heap[10]={0,2,7,1,3,2};
//	heapinsert(heap,2);
//	heapinsert(heap,7);
//	heapinsert(heap,1);
//	heapinsert(heap,3);
//	heapinsert(heap,2);
    heapsize=5;
    for(int i=heapsize;i>=1;i--){
    	heapify(heap,i);
	}
//	heapsort(heap);
//	for(int i=1;i<=5;i++){
//		cout<<heap[i]<<" ";
//	}
//	cout<<endl;
//	heapchange(heap,3,9);
	for(int i=1;i<=heapsize;i++){
		cout<<heap[i]<<" ";
	}
//	cout<<endl;
//	int x=heapdelete(heap); 
//	cout<<x<<endl;
//	for(int i=1;i<=heapsize;i++){
//		cout<<heap[i]<<" ";
//	}
} 

  本次分享到此结束,感谢观看,多多点赞!! 

标签:int,堆排序,heapsize,heap,left,maxchild,节点,结构
From: https://blog.csdn.net/weixin_74901355/article/details/143081167

相关文章

  • AirTable、维格表、SeaTable等智能表格产品,数据库结构是怎样的
    AirTable、维格表、SeaTable等智能表格产品,数据库结构是怎样的:AirTable、维格表、SeaTable等智能表格产品的数据库结构是基于关系型数据库设计的,其数据模型通常由一张或多张表格组成,每个表格都有一个名称和一些列。一、AirTable、维格表、SeaTable等智能表格产品,数据库结构是......
  • java堆排序的示例代码
    publicclassHeapSort{publicstaticvoidmain(String[]args){int[]arr={12,11,13,5,6,7};System.out.println("Originalarray:");for(intvalue:arr){System.out.print(value+"");......
  • 数据结构与算法之线性表的基本操作
    数据结构之线性表的基本操作初始化,插入,获取#include<stdio.h>#include<stdlib.h>#include<malloc.h>#defineOK1#defineOVERFLOW-1#defineLIST_INIT_SIZE100#defineLISTINCREMENT10typedefintElemType;typedefstruct{ ElemType*elem; intlength; i......
  • 通过结构化数据构建页面
    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(MaoistLearning)➤博客园地址:为敢技术(https://www.cnblogs.com/strengthen/ )➤GitHub地址:https://github.com/strengthen➤原文地址:https://www.cnblogs.com/strengthen/p/......
  • 【高阶数据结构】揭开红黑树‘恶魔’的面具:深度解析底层逻辑
    高阶数据结构相关知识点可以通过点击以下链接进行学习一起加油!二叉搜索树AVL树大家好,我是店小二,欢迎来到本篇内容!今天我们将一起探索红黑树的工作原理及部分功能实现。红黑树的概念相对抽象,但只要我们一步步深入,定能慢慢揭开它的神秘面纱......
  • 高清图解28个高并发之数据结构/数据结构场景匹配技巧分析(高并发精通篇三)
    Java中的Map家族包括基于哈希表的HashMap,维护插入顺序的LinkedHashMap,基于红黑树的TreeMap,线程安全的Hashtable和ConcurrentHashMap,以及基于身份比较的IdentityHashMap和基于弱引用的WeakHashMap。Queue家族则涵盖了Vector、Stack、Properties以及多种List和Deque实现,适用......
  • Scanner键盘录入和语句结构体
    一、键盘录入importjava.util.Scanner;/*键盘录入:程序运行过程中,用户可以根据自己的需求输入参与运算的值今天只需要掌握如何使用即可,不需要关系细节,后面会再说实现键录入的步骤:1、导包2、创建键盘录入对象3、调用方法实现键盘......
  • 02.数据结构介绍&顺序表、链表简述+对比
    目录一、什么是数据结构二、线性表三、顺序表四、链表五、顺序表和链表的区别一、什么是数据结构          数据结构是由“数据”和“结构”两个词组合而来。    数据:常见的数值1、2、3......,网页里的文字图片信息等都是数据。    ......
  • 【数据结构】分治算法经典: 快速排序详解
    快速排序(Quicksort)是一种高效的排序算法,最早由TonyHoare在1960年提出。它采用了分治(DivideandConquer)策略,平均时间复杂度为O(nlog......
  • 类、结构体、指针
    1、类的定义classPerson{ private: intage,height; doublemoney; stringbooks[100]; public: stringname; voidsay() { cout<<"I'm"<<name; } intget_age() { returnage; } voidadd_money(doublex) { ......