堆排序实现

#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); 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值