堆排序

 

  最近也参加了一些公司去笔试,发现很多公司都喜爱考查“堆排序”这玩意儿,特地花一点儿时间学习并自己亲自写代码去实现。

  这里的堆结构是二叉堆,是一种完全二叉树的数据结构,堆排序分为两部分,第一部分是建堆,可以根据要求建成大根堆或小根堆;第二部分就是排序了。堆排序是用数组模拟树的结构来进行排序的。

  建堆过程:从编号更大的节点开始更新,取其左右孩子大者交换位置不断更新直到当前节点的值大于左右孩子节点权值或更新到了叶子节点。

  排序过程:不断取出根节点元素,每取出一个根节点元素就将尾节点元素放到根并更新堆。

 

/*
    堆排序实现
*/
#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
using namespace std;
#define pii         pair<int,int>
#define clr(a)      memset((a),0,sizeof (a))
#define rep(i,a,b)  for(int i=(a);i<=(int)(b);i++)
#define per(i,a,b)  for(int i=(a);i>=(int)(b);i--)
#define oo          0x3f3f3f3f
#define eps         1e-6
#define N           100005
#define M           100005
#define mod         1000000007
#define MP          make_pair
#define PB          push_back
#define RI(x)       scanf("%d",&x)
#define RII(x,y)    scanf("%d%d",&x,&y)
#define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z)
typedef long long LL;

int a[N];

void update(int cur, int n)    // 从编号为cur的节点不断向下更新知道不能更新为止,用非递归实现效率会高很多
{
    while(1)
    {
        int lson = cur << 1;
        int rson = cur << 1 | 1;
        bool flag = false;     // 标记是否进行了交换操作
        if(lson <= n && rson <= n)
        {
            if(a[lson] >= a[rson] && a[lson] > a[cur])      // 左孩子节点不小于右孩子节点,和左孩子交换权值并跳到左孩子
            {
                swap(a[cur], a[lson]);
                cur = lson;
                flag = true;
            }
            else if(a[rson] >= a[lson] && a[rson] > a[cur]) // 右孩子节点不小于左孩子节点,和右孩子交换权值并跳到右孩子
            {
                swap(a[cur], a[rson]);
                cur = rson;
                flag = true;
            }
        }
        else if(lson <= n && rson > n)  // 如果没有右孩子而且可以向左孩子更新
        {
            if(a[lson] > a[cur])
            {
                swap(a[cur], a[lson]);
                cur = lson;
                flag = true;
            }
        }
        if(!flag) break;                // 没有出现交换操作,跳出循环
    }
}

void build(int n)
{
    int st = n;    // 要更新的位置其实是非叶子节点,但不好操作,直接从最后一个节点一路向上更新吧,反正复杂度不变
    for(int i = st; i >= 1; i--)
        update(i, n);
}

void hsort(int n)  // 堆排序,不断地取出根节点,把尾部节点移到根节点并更新堆
{
    int m = n;
    while(m > 1)
    {
        swap(a[1], a[m]);
        m--;      // 尾节点编号不断前移 n->1
        update(1, m);
    }
}

int main()
{
int n = 0, v; while(scanf("%d", &v) != EOF) a[++n] = v; build(n); hsort(n); rep(i,1,n) printf("%d ", a[i]); return 0; }

 

  这个博客介绍得很详细,图文并茂:http://www.cnblogs.com/Anker/archive/2013/01/23/2873422.html

posted @ 2013-10-08 15:43  芒果布丁  阅读(263)  评论(0编辑  收藏  举报