浅谈堆排序

浅谈堆排序

什么是堆

1.堆的特点

​ (1).堆是一颗完全二叉树

​ (2).堆的父节点大于左右子节点(大根堆)左右子节点大小无序

const int MaxSize=1000;
int heap[MaxSize]; //下标从1开始
int n;  //表示堆中的节点的个数,也是heap数组的长度

2.基本知识

​ 对于一颗用数组(下标从1开始)存储的堆,假设某节点为 heap[ i ]

​ 则父节点为 heap[ i / 2] 左儿子节点为 heap[ i * 2 ] 右儿子节点为 heap[ i * 2 +1]

怎么建堆

1.先介绍几个基本操作

(1)Swap操作

​ 交换下标为 i , j 的节点的值

void Swap(int heap[],int i,int j)
{
    int temp=heap[i];
    heap[i]=heap[j];
    heap[j]=temp;
}
(2)Adjust操作

​ 一个以index为根节点的堆,将index与更大的儿子节点向下交换,直到为叶子节点或者当前节点大于左右儿子节点。

void Adjust(int heap[],int n,int index)
{
    while(index<=n)
    {
        int left=index*2;		//左儿子
    	int right=index*2+1;	//右儿子
        
        //当右儿子存在,且最大,根节点与右儿子交换,并且新的根节点是右儿子
        if(right<=n&&heap[right]>heap[left]&&heap[right]>heap[index])
        {
            Swap(heap,index,right);
            index=right;
        }
        //左儿子大于根节点,右儿子不存在或右儿子小于左儿子
        else if(left<=n&&heap[left]>heap[index]&&(right>n||heap[left]>heap[right]))
        {
            Swap(heap,index,left);
            index=left;
        }
        else
        	break;
        
    }
}
(3)Heap_Insert操作

对于一个已经建好的堆,插入一个值为x的新节点

先将x放在堆的最后新加的一个节点,然后逐层向上比较交换

void Heap_Insert(int heap[],int n,int x)
{
	int temp=n+1;
	heap[temp]=x;
	while(temp>1&&heap[temp]>heap[temp/2])	//当前节点大于父节点 且当前节点不是堆顶 就继续向上交换
	{
		Swap(heap,temp,temp/2);
		temp/=2;
	}
}

2.两种建堆的方法

(1)多次调整建堆

从最后一个节点的父节点开始,递减的对每个节点进行一次Adjust

void Build_Heap(int heap[],int n)
    for(int i=n/2;i>0;i--)
        Adjust(heap,n,i);
}
(2)逐个insert建堆

逐个将后面的节点加入前面已经建好的堆

void Build_Heap(int heap[],int n)
{
	for(int i=1;i<n;i++)
		Heap_Insert(heap,i,heap[i+1]);
}

给堆排序

我们知道,虽然堆本身有一定的特点,父节点大于子节点,但是从上往下遍历不一定是有序的。

堆排序是对于一个已经建好的堆,进行两步操作

1.交换堆顶节点和最后一个节点,把最后一个节点剔出堆

2.然后新的堆顶元素进行调整


void Heap_sort(int heap[],int n)
{
	for(int i=n;i>0;i--)
	{
		Swap(heap,1,i);
		Adjust(heap,i-1,1);
	}
}

注意:大根堆排序后是从小到大,小根堆排序后是从大到小

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值