一、堆
1.概念:它是一种完全二叉树(即前n-1层是满的,最后一层连续缺失右边的结点)
2.堆的目的:排序
3.堆的创建:创建一棵完全二叉树
4.存储方式:链式存储,按层存储
5.算法:建立结构体,声明结点类型
typedef struct node{
int data; //结点的值
struct node *left,*right;// 左、右子女
}
6.先创建根结点,后创建其他结点;
采用队列存储数据元素,动态创建一个队列:Q
初始化:root为根结点,左右都赋空,让pa指向根结点
遍历数据集合,创建新结点 p,看pa的左右域,先挂左子女,后挂右子女;用p实现挂结点
创建完,释放队列
BTNode* CreatDui(int a[],int n){
//链式存储
BTNode *root,*pa,*p;
BTNode **Q;
int front=0,rear=0; //首尾结点都置零
root=(BTNode*)malloc(sizeof(BTNode)); //创建根结点
root->data=a[0];
root->left=root->right=NULL;
pa=root; //指针pa指向root结点
//遍历数据集合
for(int i=0;i<n;i++){
//创建新结点
p=(BTNode*)malloc(sizeof(BTNode));
p->data=a[i];
p->left=p->right=NULL;
//找双亲,判断左右
if(!pa->left)
pa->left=p;
else(!pa->right){
pa->right=p;
pa=Q[++front];
}
Q[++rear]=p;
}
二、小根堆
即:根节点小于左右结点
1. 再次借助于队列,队列存的是结点指针,front和rear两个队列指针,初始front=0;rear=0;
首先使创建好的完全二叉树的所有结点的入队列,结果是:front在第一个叶子上,rear在最后一个结点元素上
将end放在队列的尾部,即排序后最小的元素上,使队尾标志不丢失:end=rear;
然后调整堆:比较双亲和子女的大小
小根堆完整代码:
#include<stdlib.h>
#include<stdio.h>
#define N 20
typedef struct node{
int data;
struct node *left;
struct node *right;
}BTNode;
//创建完全二叉树
BTNode* CreatDui(int a[],int n){
//链式存储
BTNode *root,*pa,*p,*pm;
int end,tag,k,m,t;
BTNode **Q;
Q=(BTNode**)malloc(N*sizeof(BTNode*));
int front=0,rear=0;
root=(BTNode*)malloc(sizeof(BTNode));
root->data=a[0];
root->left=root->right=NULL;
pa=root;
for(int i=1;i<n;i++){
p=(BTNode*)malloc(sizeof(BTNode));
p->data=a[i];
p->left=p->right=NULL;
if(!pa->left)//找双亲,判断左右
pa->left=p;
else{
pa->right=p;
pa=Q[++front];
}
Q[++rear]=p;
}
return root;
free(Q);
}
//堆排序
void duiSort(BTNode *root){
BTNode **Q,*p,*pm;
int front=0,rear=0,t,tag,end,k,m;
Q=(BTNode**)malloc(N*sizeof(BTNode*));
Q[++rear]=root; //根节点先入队列
while(1)
{
p=Q[++front]; // 父节点入队列
if(p->left)
{
Q[++rear]=p->left; //当父节点有左孩子时,左孩子入队列
}
if(p->right)
{
Q[++rear]=p->right; //当父节点有右孩子时,右孩子入队列
}
if(!p->left&&!p->right) //当父节点无左右子女时,二叉树存入队列结束,跳出循环
break;
}
//结果:front指第一个叶子,rear在最后一个元素/叶子上
end=rear;
//调整堆
while(front>1){
while(1){
tag=1;
for(k=front-1;k>0;k--){
p=Q[k];
pm=p;
if(p->data>p->left->data)
pm=p->left;
if(p->right&&p->right->data<pm->data)
pm=p->right;
if(p-pm){
t=pm->data;
pm->data=p->data;
p->data=t;
tag=0;
}
}
if(tag)
break;
}
//交换
m=root->data;
root->data=Q[rear]->data;
Q[rear]->data=m;
rear--;
//去叶子
if(Q[front-1]->right)
Q[front-1]->right=NULL;
else{
Q[front-1]->left=NULL;
front--;
}
}
//输出
for( ;end>0;end--)
printf("%d ",Q[end]->data);
}
int main(void){
int a[12]={3,2,12,7,11,8,6,1,9,13,4,5};
BTNode* Root;
Root=CreatDui(a,12);
printf("\n输出最小根堆\n");
duiSort(Root);
}