堆排序

堆排算是排序算法中比较难的一个算法,在实现编码之前首先要对堆排的思想有一个清晰的思路,下面我们就来分析一下堆排序。

   1.首先要明白堆排序第一步要有堆,也就是完全二叉树,那么问题来了,如何创建一个完全二叉树呢完全二叉树是需要按层来创建的,如果你曾经编写过按层遍历二叉树这块会很好理解,按层的话要记录上一个结点,所以要用到     队列,创建的节点依次入队。

   2.创建好完全二叉树,堆排已经完成了1/3了。第二步我们就要对创建好的完全二叉树进行调整,把它调整成大根堆(或者小根堆)从最后一个双亲节点(注意这里所说的双亲结点是指只要它不是叶子,它至少有一个孩子节点)开始,在他的孩子节点和它本身找到数据域的最大值,赋值给双亲结点,再找倒数第二个双亲节点,即此时队列里前一个元素,直到根节点。这时第一遍循环完,再从最后一个双亲开始,重复上面的过程,直到有一遍没有交换操作。(没有交换操作说明此时是大根堆)

    3.最后一步,排序,2过程进行完后,根节点就是数据域最大值的节点了,ok,输出它的data,然后把它和最后一个叶子节点进行交换,删掉最后一个叶子,此时,堆已经不是大根堆了,好,再重复2过程,再重复3过程。直到完全二叉树只剩下最后一个节点,输出。堆排就写好了。

     下面是重点部分源代码:



typedef struct node
{
int data;
struct node *left;
struct node *right;

}BTNode;


int front=0,rear=0;//设置成全局变量


//创建完全二叉树,按层创建
BTNode * creatBTree(int D[],int n,BTNode * * Q)
{
BTNode * r,* t,* p;
int i;
t=NULL;
r=(BTNode * )malloc(sizeof(BTNode ));
r->data=D[0];
r->left=r->right=NULL;
Q[++rear]=r;
    for(i=1;i<n;i++)


if(t==NULL){t=Q[++front]; }//t用来记录此时创建的结点的双亲

p=(BTNode * )malloc(sizeof(BTNode ));
p->data=D[i];
p->left=p->right=NULL;
if(t->left==NULL)t->left=p;
else{t->right=p;t=NULL; }
Q[++rear]=p;
}
    return r;

}




//调整堆 


void pHeap(BTNode * r,BTNode * * Q)
{
int tag,k,m;
BTNode * t;
//k=front;
while(1)
{
tag=0;
k=front;//front记录的值是最后一个双亲
while(k>0)
{
t = Q[k];//注意每次t值得更新,但此时front不能动,用来记录树里面最后一个双亲节点
if(t->data<t->left->data)
{
//交换
m=t->data;
t->data=t->left->data;
t->left->data=m;
tag=1;

}
if(t->right&&t->data<t->right->data)
{
m=t->data;
t->data=t->right->data;
t->right->data=m;
tag=1;//tag值用来记录这一趟是否执行了交换操作

}
k--;
}
if(!tag) break;//直到调整成堆

}

}




void sort(BTNode * r,BTNode * * Q)
{

int m;
BTNode * t,*q;
//交换根结点和最后一个叶子的值
/* while (front > 1){
pHeap(r,Q); //调整大根堆
//printf("%d\n", r->data);
// getchar();
m=Q[rear]->data;
Q[rear]->data=r->data;
r->data=m;
if (Q[front]->right){
Q[front]->right = NULL;
}
else{
Q[front]->left = NULL;
front--;
}
rear--;

}*/

//被注释掉的这一段是实现排序的另一种方法




while(r->left)//当只剩下最后一个结点
{
printf("%5d",r->data);
//交换根节点和最后一个叶子节点的数据域
m=Q[rear]->data;
Q[rear]->data=r->data;
r->data=m;rear--;
t=Q[front];
if(t->right)//删掉you边结点
{
q=t->right;
t->right=NULL;


}
else
{

q=t->left;
t->left=NULL;
//free(q);
t=Q[--front];
}
pHeap(r,Q);//调整堆
}
printf("%5d",r->data);


}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值