自建堆排序:

Posted xuan01

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自建堆排序:相关的知识,希望对你有一定的参考价值。

建堆(heapification):

蛮力算法

空堆反复调用insert()接口,消耗时间过多,第k轮迭代需O(logK)时间,正比于其深度:总共需要O(log n!) = O(n log n);同理于自顶向下、自左向右的上滤操作;

实现时先入一个最大值元素,放在下标为0的地方,此后,元素从下标为1 的地方进行建堆,假设父节点下标是 i,则左右子节点 是2*i,2*i+1;

class Priority_ueue
private:
    int heap_size;
    vector<int>heap;
public:
    Priority_ueue()
        heap.push_back(INT_MAX);
        heap_size = 0;
    
    void insert(int num)
        heap.push_back(num);
        ++heap_size;
        int tmp = heap_size;
        for(;num > heap[tmp/2];tmp /= 2)
            heap[tmp] = heap[tmp/2];
        
        heap[tmp] = num;
    //上滤
    int delmax()
        if(heap_size == 0)
            cout << "delmax error!" << endl;
            return INT_MAX;
        else
            int res = heap[1];
            int num = heap[heap_size--];
            heap.pop_back();
            int pos = 1, tmp = pos*2;
            while(tmp < heap_size)
                if(tmp+1 <= heap_size) tmp = heap[tmp] > heap[tmp+1] ? tmp : tmp + 1;
                if(num < heap[tmp])
                    heap[pos] = heap[tmp];
                    pos = tmp;
                    tmp *= 2;
                else
                    break;
                
            //下滤
            heap[pos] = num;
            return res;
        
    
    bool empty()
        return heap_size == 0;
    
    int size()
        return heap_size;
    
;

测试样例:

int main()
    int tmp;
    Priority_queue q;
    while(cin >> tmp)
        q.insert(tmp);
    
    while(!q.empty())
        cout << q.delmax() << endl;
    
    return 0;

floyd算法:

 自下而上的、下滤操作:对所有的节点进行一次下滤, 每个节点下滤所需的时间正比于其高度,故总体运行时间取决于高度总和;相较于蛮力算法,深度小的节点远远少于高度小的节点

 

建堆,以及对堆排序

                                        建堆,以及堆排序

代码1:
#include<stdio.h>
int h[101];//用来存放堆的数组 
int n;//用来存储堆中元素的个数,就是堆的大小 
//交换函数,用来交换堆中的俩个元素的值 
void swap(int x,int y)
{
	int t;
	t=h[x];
	h[x]=h[y];
	h[y]=t;
}
//向下调整函数 
void siftdown(int i)
{//传入一个须要向下调整的的节点编号i,这里传入1。即从堆的顶点開始向下调整 
	int t,flag=0;//flag用来标记是否须要继续向下调整
	//当i节点有儿子(事实上是至少有左儿子)而且有须要继续调整的时候循环就运行 
	while(i*2<=n&&flag==0)
	{
		//首先推断它与左儿子的关系。而且t记录值比較小的节点编号 
		if(h[i]>h[i*2])
		{
			t=i*2;
		}
		else
	    {
	    	t=i;
		}
		//假设它有右儿子,再对右儿子进行讨论 
		if(i*2+1<=n)
		{
			//假设右儿子的值更小。更新较小的节点编号 
			if(h[t]>h[i*2+1])
			{
				t=i*2+1;
			}
		}
		//假设发现最小的结点编号不是自己,说明子结点中有比父节点更小的值 
		if(t!=i)
		{
			swap(t,i);//交换他们。注意swap函数 
			i=t;//更新i为刚才与它交换的儿子结点的编号。便于接下来继续向下调整 
		}
		else
		{
			flag=1;
			//否则说明当前的父结点已经比俩个子结点都要小了,不须要再进行调整 
		}
	}	
} 
//建立堆函数 
void creat()
{
	int i;
	for(i=n/2;i>=1;i--)
	{
		//总最后一个非叶结点到第一个结点一次进行向上调整 
		siftdown(i);
	}
}
//删除最大的元素 
int deletemax()
{
	int t;
	t=h[1];//用一个暂时变量记录堆顶点的值 
	h[1]=h[n];//将堆的最后一个点赋值给堆顶 
	n--;//堆的元素降低1 
	siftdown(1);//向下调整 
	return t;//返回之前记录的堆的顶点的最大值 
}
int main()
{
	int i,num;
	scanf("%d",&num);
	for(i=1;i<=num;i++)
	{
		scanf("%d",&h[i]);
	}
	n=num;
	creat();
	for(i=1;i<=num;i++)
	{//删除顶部元素,连续删除n次,事实上也就是从大到小的把数输出 
		printf("%d ",deletemax());
	}
	return 0;
}
代码,2:
#include<stdio.h>
int h[101]; //用来存储堆的数组
int n;//用来存储堆中的元素的个数,也就是堆的大小
//交换函数,用来交换堆中的俩个元素的值
void swap(int x,int y)
{
	int t;
	t=h[x];
	h[x]=h[y];
	h[y]=t;
} 
//向下调整函数 
void siftdown(int i)
{//传入一个须要向下调整的的节点编号i,这里传入1,即从堆的顶点開始向下调整 
	int t,flag=0;//flag用来标记是否须要继续向下调整
	//当i节点有儿子(事实上是至少有左儿子)而且有须要继续调整的时候循环就运行 
	while(i*2<=n&&flag==0)
	{
		//首先推断它与左儿子的关系,而且t记录值比較小的节点编号 
		if(h[i]<h[i*2])
		{
			t=i*2;
		}
		else
	    {
	    	t=i;
		}
		//假设它有右儿子。再对右儿子进行讨论 
		if(i*2+1<=n)
		{
			//假设右儿子的值更大,更新较小的节点编号 
			if(h[t]<h[i*2+1])
			{
				t=i*2+1;
			}
		}
		//假设发现最小的结点编号不是自己,说明子结点中有比父节点更小的值 
		if(t!=i)
		{
			swap(t,i);//交换他们,注意swap函数 
			i=t;//更新i为刚才与它交换的儿子结点的编号。便于接下来继续向下调整 
		}
		else
		{
			flag=1;
			//否则说明当前的父结点已经比俩个子结点都要小了,不须要再进行调整 
		}
	}	
} 
//建立堆函数 
void creat()
{
	int i;
	for(i=n/2;i>=1;i--)
	{
		//总最后一个非叶结点到第一个结点一次进行向上调整 
		siftdown(i);
	}
}
//堆排序
void heapsort()
{
	while(n>1)
	{
		swap(1,n);
		n--;
		siftdown(1);
	}
 } 
 int main()
 {
 	int i,num;
 	scanf("%d",&num);
 	for(i=1;i<=num;i++)
 	{
 		scanf("%d",&h[i]);
	}
	n=num;
	creat();//建堆
	heapsort();//堆排序
	for(i=1;i<=num;i++)
	{
		printf("%d ",h[i]);
	 } 
	 return 0;
 }



以上是关于自建堆排序:的主要内容,如果未能解决你的问题,请参考以下文章

建堆-时间复杂度 堆排序时间复杂度

c++ 手写堆 (包括建堆排序添加元素删除元素)

堆排序和TOP-K问题

堆排序和TOP-K问题

堆+建堆插入删除排序+java实现

建堆复杂度O(n)证明