#include<stdio.h>
#include<stdlib.h>
#define N 9
#define MAX 15
typedef int datatype;
typedef struct node{
datatype data;
struct node* left;
struct node* right;
}BTNode;
//创建一棵完全二叉树
void CreateTree(BTNode **root, int a[]){ //int = a[N]
BTNode *p, *pa;
BTNode **Q; //队列 ,指向指针数组
int front, rear; //队的首尾
printf("创建一棵完全二叉树\n");
Q = (BTNode**)malloc((N+2) * sizeof(BTNode*));
front = rear = 0;
//创建根节点
pa = *root = (BTNode*)malloc(sizeof(BTNode));
(*root)->data = a[0];
(*root)->left = (*root)->right = NULL;
printf("根结点%d创建成功。\n", (*root)->data);
for (int i = 1; i < N; i++){ //循环 N-1 次,总共N个结点,生成一个完全二叉树
p = (BTNode*) malloc (sizeof (BTNode));
p->data = a[i];
p->left = p->right = NULL;
p->left = p->right = NULL;
if(!pa->left) //左树空先给左子树赋值
{
pa->left = p;
printf("结点%d左孩子为:%d。\n",pa->data ,p->data );
}
else{
pa->right = p;
printf("结点%d右孩子为:%d。\n",pa->data ,p->data );
pa = Q[++front];
}
Q[++rear] = p;
}
}
//层次遍历二叉树T,从第一层开始,每层从左到右遍历
void LevelOrder(BTNode* T) {
printf("\n层次遍历二叉树:\n");
BTNode** Queue,* p;
//用一维数组表示队列,front和rear分别表示队手和队尾指针
Queue = (BTNode**)malloc(N * sizeof(BTNode*)) ;
int front, rear;
front = rear = 0;
if (T != NULL) { //若树非空
Queue[++rear] = T; //根节点入队
while (front != rear) { //当队列非空
p = Queue[++front]; //队首元素出队
printf("%5d", p->data);
if (p->left != NULL) //左子树非空,则入队
Queue[++rear] = p->left;
if (p->right != NULL) //右子树非空,则入队
Queue[++rear] = p->right;
}
}
//free(Queue);
}
//堆排序
//将跟结点的而地址依次存入
void pile(BTNode *root){
printf("\n开始堆排序\n");
BTNode *p ; //遍历二叉树
BTNode** Q;
//声明队列并初始化,队列用来存储结点地址,
Q = (BTNode**)malloc((N+1) * sizeof (BTNode*));
int front , rear;
//front记录第一个队列元素前面一个位置的下标, rear则记录最后一个元素下标
front = rear = 0;
//按层遍历,将完全二叉树存入队列
//根入队
Q[++rear] = root;
printf("\n层次c存入二叉树结点:\n");
//其他节点
while(1){
p = Q[++front];
//当p指向叶子结点时,所有的结点都存入到队列中,此时便可结束while循环
if(p->left == NULL && p->right == NULL){ //结点为非叶子结点时
break;
}
printf("%5d", p->data);
if(p->left){
Q[++rear] = p->left; //左节点入队
}
if(p->right){
Q[++rear] = p->right; //右结点入队
}
}
//调整后的结果为:
//front 指向第一个叶子结点,
//front-1 指向最后一个parent结点,
//rear只最后一个叶子节点
printf("\n以上输出结点为parent结点。\n");
int end = rear; //设置队尾岗哨 end = rear,用于排序结束后的输出
BTNode* pmin = NULL; //调整二叉树时,用来标记最小值结点
datatype temp = 0;
//堆排序
while(1){
int flag = 1;
//1.将堆调整为小根堆
while(flag){
flag = 0;
//找最小值结点 给pmin
for (int k = front - 1; k > 0; k--){
p = Q[k];
if(p->right != NULL){ //右子树不空比较三个节点
pmin = p->data < p->left->data ? p : p->left;
pmin = pmin->data < p->right->data ? pmin : p->right;
}else{ //右子树空,比较两个结点
pmin = p->data < p->left->data ? p : p->left;
}
//交换,将较小的的结点往上层换
if(p != pmin){
temp = p->data;
p->data = pmin->data;
pmin->data = temp;
flag = 1; //flag = 1 表示本次循环有交换操作,当一趟while循环下来,flag 依然为0, //这表示该二叉树已经为一颗小根堆
}
}
}
//2.交换根节点和最后一个叶子结点
temp = root->data ;
root->data = Q[rear]->data;
Q[rear]->data = temp;
//3.砍最后一个parent结点的叶子结点
//砍掉的叶子结点即为已经拍好序的结点
//a.右不为空:砍右结点,rear - -
if(Q[front-1]->right != NULL){
Q[front-1]->right = NULL;
rear--;
}
//b.右空,左不为空:砍左结点,front - -,rear - -
else{
Q[front-1]->left = NULL;
rear--;
front--;
}
if(front == rear){
break;
}
}
//因为排好序后队列时降序排列,要得升序列需反向输出
printf("输出堆排序结果:\n");
for ( ; end > 0; end--){
printf("%5d", Q[end]->data);
}
}//pile
// 先序输出二叉树
void Preorder (BTNode *root){
if(root){
printf("%5d", root->data);
Preorder(root->left);
Preorder(root->right);
}
}
int main (void){
int arr[] = {7,4,1,8,5,2,9,3,6};
BTNode *root = NULL;
CreateTree(&root,arr);
printf("%先序输出二叉树\n");
Preorder (root);
//LevelOrder(root);
pile(root);
}