统一C语言风格定义各种数据结构及基本操作——二叉树基本操作

/*bittree.h*/
#pragma once
#include<stdio.h>
#include<stdlib.h>

#define MAXNODE 10
typedef int ElemType;
typedef struct BitNode {//二叉树存储结构定义
	ElemType data;
	struct BitNode *lchild, *rchild;
}BitNode,*BitTree;
//初始化空树,1表示初始化成功,0表示初始化失败
int initTree(BitTree bt)
{
	bt = (BitNode*)malloc(sizeof(BitNode));
	if (!bt)return 0;
	bt->lchild = NULL;
	bt->rchild = NULL;
	return 1;
}
//生成一棵二叉树,根节点的数据域为e,lbt、rbt为左右子树
BitTree createTree(ElemType e, BitTree lbt, BitTree rbt)
{
	BitNode* bn = (BitNode*)malloc(sizeof(BitNode));
	if (!bn)return NULL;
	bn->data = e;
	bn->lchild = lbt;
	bn->rchild = lbt;
	return bn;
}
//在二叉树bt中插入一个结点,该节点为结点parent的左子节点,数据域为e.成功返回1,不成功返回0
int insertLeftChild(BitTree bt, ElemType e, BitTree parent)
{
	if (parent == NULL) {
		printf("\n插入失败!\n"); return NULL;
	}
	BitNode* bn = (BitNode*)malloc(sizeof(BitNode));
	if (!bn)return 0;
	bn->data = e;
	bn->lchild = NULL;
	bn->rchild = NULL;
	if (!parent->lchild) {//若parent节点的左子节点为空
		parent->lchild = bn;//将新增节点作为parent的左子节点
	}
	else {//若parent节点的左子节点不为空
		bn->lchild = parent->lchild;//将parent的左子树作为新增节点的左子树
		parent->lchild = bn;//将新增节点作为parent的左子节点
	}
	return 1;
}
//在二叉树bt中插入一个结点,该节点为结点parent的右子节点,数据域为e.成功返回1,不成功返回0
int insertRightChild(BitTree bt, ElemType e, BitTree parent)
{
	if (!parent) {
		printf("\n插入出错!\n"); return NULL;
	}
	BitNode* bn = (BitNode*)malloc(sizeof(BitNode));
	if (!bn)return 0;
	bn->data = e;
	bn->lchild = NULL;
	bn->rchild = NULL;
	if (!parent->rchild) {//若parent节点的右子节点为空
		parent->rchild = bn;//将新增节点作为parent的右子节点
	}
	else {//若parent节点的右子节点不为空
		bn->rchild = parent->rchild;//将parent的右子树作为新增节点的右子树
		parent->rchild = bn;//将新增节点作为parent的右子节点
	}
	return 1;
}
/************************************************遍历二叉树************************************************/
void tprint(ElemType e)//输出
{
	printf("%d ", e);
}
//前序遍历
void preTraverseTree(BitTree bt,void(*callback)(ElemType))
{
	if (!bt)return;
	(*callback)(bt->data);
	preTraverseTree(bt->lchild, callback);
	preTraverseTree(bt->rchild, callback);
}
//中序遍历
void inTraverseTree(BitTree bt, void(*callback)(ElemType))
{
	if (!bt)return;	
	inTraverseTree(bt->lchild, callback);
	(*callback)(bt->data);
	inTraverseTree(bt->rchild, callback);
}
//后序遍历
void postTraverseTree(BitTree bt, void(*callback)(ElemType))
{
	if (!bt)return;
	postTraverseTree(bt->lchild, callback);	
	postTraverseTree(bt->rchild, callback);
	(*callback)(bt->data);
}
//层序遍历二叉树(在这里使用队列的思想)
void levelTraverseTree(BitTree bt)
{
	BitTree queue[MAXNODE];
	int front = -1, rear = 0;//队列队首游标、队尾游标
	queue[rear] = bt;
	while (front != rear) {
		front++;//队首游标不断向队尾移动
		printf("%d ", queue[front]->data);//输出队首游标指向结点的数据域
		if (queue[front]->lchild != NULL)queue[++rear] = queue[front]->lchild;//若队首游标指向结点的左子节点不为空,则将该左子节点压入队列尾部
		if (queue[front]->rchild != NULL)queue[++rear] = queue[front]->rchild;//若队首游标指向结点的右子节点不为空,则将该右子节点压入队列尾部
	}
}
/*****************************************************删除二叉树****************************************************/
//用后序遍历删除子树(只能用后序遍历,否则一旦先释放根节点,子节点就无法找到了)
void postTraverseTree(BitTree bt, void(*callback)(BitTree))
{
	if (!bt)return;
	postTraverseTree(bt->lchild, callback);
	postTraverseTree(bt->rchild, callback);
	(*callback)(bt);	
}
void release(BitTree bt)//释放结点空间
{
	//printf("%d ", bt->data);
	free(bt);//删除节点
}
//在二叉树bt中删除以parent结点为父节点的左子树
int deleteLeftTree(BitTree bt, BitTree parent)
{
	if (parent == NULL || parent->lchild == NULL) {
		printf("\n删除失败!\n"); return 0;
	}
	BitNode* bn = parent->lchild;
	parent->lchild = NULL;
	//printf("%d", bn->data);///
	postTraverseTree(bn, release);//遍历并删除节点
	//printf("%d", bn->data);/通过前后打印对比可以发现bn已经被释放了
	//free(bn);
	bn = NULL;
	return 1;
}
//在二叉树bt中删除以parent结点为父节点的右子树
int deleteRightTree(BitTree bt, BitTree parent)
{
	if (parent == NULL || parent->rchild == NULL) {
		printf("\n删除失败!\n"); return 0;
	}
	BitNode* bn = parent->rchild;
	parent->rchild = NULL;
	//printf("%d", bn->data);///
	postTraverseTree(bn, release);//遍历并删除节点
	//printf("%d", bn->data);/通过前后打印对比可以发现bn已经被释放了
	//free(bn);//已释放,再次释放会报错
	bn = NULL;
	return 0;
}
/*main.cpp*/
#include"bittree.h"
int main()
{
	BitNode* bn;
	int i, e, state, num,p;
	printf("请输入二叉树结点的个数:");
	scanf("%d", &num);
	printf("请输入根节点的元素值:");
	scanf("%d", &e);

	bn= createTree(e,NULL,NULL);

	for (i = 1; i < num; i++) {
		printf("\n第%d个结点插入的位置为:\n"
			   "1、作为根节点的左子树\n"
			   "2、作为根节点的右子树\n"
		       "3、作为根节点左子树的左子树\n"
		       "4、作为根节点左子树的右子树\n"
		       "5、作为根节点右子树的左子树\n"
		       "6、作为根节点右子树的右子树\n"
		       "(1~6):",i+1);
		scanf("%d", &p);
		printf("请输入节点的元素值:");
		scanf("%d", &e);
		switch (p)
		{
		case 1:	state=insertLeftChild(bn, e, bn); break;
		case 2: state=insertRightChild(bn, e, bn); break;
		case 3:state=insertLeftChild(bn, e, bn->lchild); break;
		case 4:state=insertRightChild(bn, e, bn->lchild); break;
		case 5:state=insertLeftChild(bn, e, bn->rchild); break;
		case 6:state=insertRightChild(bn, e, bn->rchild); break;
		default:
			break;
		}
		if (state == 0)i--;
	}

	printf("先序遍历二叉树:");
	preTraverseTree(bn, tprint);
	printf("\n");

	printf("中序遍历二叉树:");
	inTraverseTree(bn, tprint);
	printf("\n");

	printf("后序遍历二叉树:");
	postTraverseTree(bn, tprint);
	printf("\n");

	printf("层序遍历二叉树:");
	levelTraverseTree(bn);
	printf("\n\n");

	printf("删除节点所在的位置为:\n"
		"1、作为根节点的左子树\n"
		"2、作为根节点的右子树\n"
		"3、作为根节点左子树的左子树\n"
		"4、作为根节点左子树的右子树\n"
		"5、作为根节点右子树的左子树\n"
		"6、作为根节点右子树的右子树\n"
		"(1~6):");
	scanf("%d", &p);
	switch (p)
	{
	case 1:	deleteLeftTree(bn,  bn); break;
	case 2: deleteRightTree(bn, bn); break;
	case 3:deleteLeftTree(bn, bn->lchild); break;
	case 4:deleteRightTree(bn, bn->lchild); break;
	case 5:deleteLeftTree(bn, bn->rchild); break;
	case 6:deleteRightTree(bn, bn->rchild); break;
	default:
		break;
	}

	printf("先序遍历二叉树:");
	preTraverseTree(bn, tprint);
	printf("\n");

	printf("中序遍历二叉树:");
	inTraverseTree(bn, tprint);
	printf("\n");

	printf("后序遍历二叉树:");
	postTraverseTree(bn, tprint);
	printf("\n");

	printf("层序遍历二叉树:");
	levelTraverseTree(bn);
	printf("\n");

	return 1;
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值