二叉树基本操作的C语言实现(删除节点、判断是否对称树)

二叉树基本操作的C语言实现

  • 功能


  1. 判断二叉树是否为空
  2. 查找数据
  3. 插入数据
  4. 删除数据
  5. 查找父亲
  6. 查找左儿子
  7. 查找右儿子
  8. 查找节点深度
  9. 二叉树深度
  10. 判断叶子结点
  11. 查找堂兄弟
  12. 清空二叉树
  13. 打印二叉树
  14. 前序遍历
  15. 中序遍历
  16. 后序遍历
  17. 转换成完全二叉树
  18. 判断是否为子树
  19. 判断是否为对称树

  • 代码

#include
#include

typedef int DataType;	// 数据类型,设为整数
typedef struct Node {	// 	
	DataType data;	// 节点数据
	struct Node *LChild; // 左子树指针
	struct Node *RChild; // 右子树指针
}BTNode, *BTree;	// 二叉树节点及二叉树指针类型


void initial(BTree *T); //初始化有序二叉树T。
int isEmpty(BTree T); //检查二叉树T 是否为空。
BTNode *search(BTree T,DataType d); //查找二叉树T 的数据为d 的节点,返回节点位址。
BTNode *insert(BTree *T,DataType d); //在二叉树T 中,插入一个数据为d 的节点, 返回新插入节点的位址。
BTNode *remov(BTree*T,DataType d); //在二叉树T 中,移除一个数据为d 的节点, 返回被移除节点的原来位址。
DataType parent(BTree T,DataType d); //取得二叉树T 中,数据为d 的节点的父亲, 返回父亲节点的数据。
DataType leftSon(BTree T,DataType d); //取得二叉树T 中,数据为d 的节点的左子树, 返回左子树根节点的数据。
DataType rightSon(BTree T,DataType d); //取得二叉树T 中,数据为d 的节点的右子树,返回右子树根节点的数据。
int depth(BTree T,DataType d); //返回二叉树T 中,数据为d 的节点的深度。
int height(BTree T); //返回二叉树T 的深度,即所有节点的最大深度。
int isLeaf(BTree T,DataType d); //对于二叉树T,判断数据为d 节点是否为叶节点。
int leafCount(BTree T); //返回二叉树T 的叶节点个数。
int allCousins(BTree T,DataType d); //对于二叉树T,打印所有数据为d 节点的堂兄弟,返回堂兄弟节点的个数。
void clearTree(BTree *T); //清除二叉树T。
void printTree(BTree T); //自上而下打印二叉树T,顺序为右子树、根节点、然后左子树;深度相同的节点数据之前要有相同个数的空格。
void preorderTraversal(BTree T); //使用前序遍历打印二叉树所有节点的数据。
void inorderTraversal(BTree T); //使用中序遍历打印二叉树所有节点的数据。
void postorderTraversal(BTree T); //使用后序遍历打印二叉树所有节点的数据。
BTree toCompletTree(BTree T); //将二叉树T 转换成完全二叉树,返回完全二叉树。
int isSubtree(BTree S, BTree T); //检查二叉树S 是否为二叉树T 的子树。
int isSymmetric(BTree T); //检查二叉树T 是否为对称树。一棵对称的二叉树是以通过根节点的垂直线为中心,两边互为镜射的树;以下为左右对称二叉树的例子。


int main() {
	printf("****************** 有序二叉树相关操作 *****************\n");
	printf("1. 判断二叉树是否为空\n");
	printf("2. 查找数据\n");
	printf("3. 插入数据\n");
	printf("4. 删除数据\n");
	printf("5. 查找父亲\n");
	printf("6. 查找左儿子\n");
	printf("7. 查找右儿子\n");
	printf("8. 查找节点深度\n");
	printf("9. 二叉树深度\n");
	printf("10. 判断叶子结点\n");
	printf("11. 查找堂兄弟\n");
	printf("12. 清空二叉树\n");
	printf("13. 打印二叉树\n");
	printf("14. 前序遍历\n");
	printf("15. 中序遍历\n");
	printf("16. 后序遍历\n");
	printf("17. 转换成完全二叉树\n");
	printf("18. 判断是否为子树\n");
	printf("19. 判断是否为对称树\n");
	printf("0. 退出\n");
	printf("****************************************************\n\n");

	BTree tree;
	initial(&tree);
	while(1) {
		printf("请输入您的选择:");
		int opt;
		scanf("%d",&opt);
		if(opt == 1) {
			printf(isEmpty(tree) ? "二叉树为空\n" : "二叉树非空\n");
			printf("\n");
		}else if(opt == 2) {
			int d;
			printf("请输入待查找数据:");
			scanf("%d",&d);
			BTree res = search(tree, d);
			if(res == NULL) printf("无此数据!\n");
			else printf("查找成功, 元素存在于二叉树!\n");
			printf("\n");
		}else if(opt == 3) {
			int d;
			printf("请输入待插入数据:");
			scanf("%d",&d);
			BTree res = insert(&tree, d);
			printf("插入 %d 成功!\n",res -> data);
			printf("\n");
		}else if(opt == 4) {
			int d;
			printf("请输入待删除数据:");
			scanf("%d",&d);
			BTree res = remov(&tree, d);
			if(res != NULL) printf("删除 %d 成功!\n",res -> data);
			printf("\n");
		}else if(opt == 5) {
			int d;
			printf("请输入待查询节点数据:");
			scanf("%d",&d);
			int k = parent(tree, d);
			if(k != -1) printf("%d 节点父亲节点数据为 %d!\n",d, k);
			else printf("无父亲!\n");
			printf("\n");
		}else if(opt == 6) {
			int d;
			printf("请输入待查询节点数据:");
			scanf("%d",&d);
			int k = leftSon(tree, d);
			if(k != -1) printf("%d 节点左儿子节点数据为 %d!\n",d, k);
			else printf("无左儿子!\n");
			printf("\n");
		}else if(opt == 7) {
			int d;
			printf("请输入待查询节点数据:");
			scanf("%d",&d);
			int k = rightSon(tree, d);
			if(k != -1) printf("%d 节点右儿子节点数据为 %d!\n",d, k);
			else printf("无右儿子!\n");
			printf("\n");
		}else if(opt == 8) {
			int d;
			printf("请输入待查询节点数据:");
			scanf("%d",&d);
			int k = depth(tree, d);
			if(k != -1) printf("%d 节点深度为 %d!\n",d, k);
			else printf("无此节点!\n");
			printf("\n");
		}else if(opt == 9) {
			printf("二叉树深度为 %d!\n", height(tree));
			printf("\n");
		}else if(opt == 10) {
			int d;
			printf("请输入待判断节点数据:");
			scanf("%d",&d);
			int k = isLeaf(tree, d);
			if(k != -1) printf(k ? "该节点是叶子结点\n" : "该节点不是叶子结点\n");
			printf("\n");
		}else if(opt == 11) {
			int d;
			printf("请输入待查找节点数据:");
			scanf("%d",&d);
			printf("%d 节点所有堂兄弟为: ",d);
			int k = allCousins(tree, d);
			printf("\n该节点有 %d 个堂兄弟!\n\n",k);
		}else if(opt == 12) {
			clearTree(&tree);
			printf("\n");
		}else if(opt == 13) {
			printTree(tree);
			printf("\n\n");
		}else if(opt == 14) {
			printf("前序遍历结果:\n");
			preorderTraversal(tree);
			printf("\n\n");
		}else if(opt == 15) {
			printf("中序遍历结果:\n");
			inorderTraversal(tree);
			printf("\n\n");
		}else if(opt == 16) {
			printf("后序遍历结果:\n");
			postorderTraversal(tree);	
			printf("\n\n");
		}else if(opt == 17) {
			tree = toCompletTree(tree); //将二叉树T 转换成完全二叉树,返回完全二叉树。
			printf("成功转化成完全二叉树\n");
			printf("\n");
		}else if(opt == 18) {
			int a,b;
			printf("请输入两个节点数据:");
			scanf("%d %d",&a,&b);
			int k = isSubtree(search(tree,a), search(tree,b)); //检查二叉树S 是否为二叉树T 的子树。
			printf(k ? "是子树\n" : "不是子树\n");
			printf("\n");
		}else if(opt == 19) {
			int k = isSymmetric(tree); //检查二叉树T 是否为对称树。一棵对称的二叉树是以通过根节点的垂直线为中心,两边互为镜射的树;以下为左右对称二叉树的例子。
			printf(k ? "是对称树\n" : "不是对称树\n");
			printf("\n");
		}else if(opt == 0) {
			break;
		}else{
			printf("输入有误!\n");
		}
	} 
}

void initial(BTree *T) //初始化有序二叉树T。
{
	*T = NULL;
}
int isEmpty(BTree T) //检查二叉树T 是否为空。
{
	return T == NULL ? 1 : 0;
}
BTNode *search(BTree T,DataType d) //查找二叉树T 的数据为d 的节点,返回节点位址。
{
	if(T == NULL) return NULL;
	//printf("%d\n",T -> data);
	if(T -> data == d) return T;
	else if(d < T -> data) return search(T -> LChild, d);
	else return search(T -> RChild, d);
}
BTNode *insert(BTree *T,DataType d) //在二叉树T 中,插入一个数据为d 的节点, 返回新插入节点的位址。
{
	BTree fa = NULL, cur = *T;
	int exist = 0;
	if(*T == NULL) {
		*T = (BTNode *)malloc(sizeof(BTNode));
		(*T) -> LChild = (*T) -> RChild = NULL;
		(*T) -> data = d; 
		return *T;
	}else{
		while(cur != NULL) {
			if(d < cur -> data) {
				fa = cur;
				cur = cur -> LChild;
			}else if(d > cur -> data){
				fa = cur;
				cur = cur -> RChild;
			}else{
				exist = 1;
				break;
			}
		}
	}
	if(exist == 1) return cur;
	if(d > fa -> data) {
		fa -> RChild = (BTNode *)malloc(sizeof(BTNode));
		fa -> RChild -> data = d;
		fa -> RChild -> LChild = fa -> RChild -> RChild = NULL;
		return fa -> RChild;
	}else{
		fa -> LChild = (BTNode *)malloc(sizeof(BTNode));
		fa -> LChild -> data = d;
		fa -> LChild -> LChild = fa -> LChild -> RChild = NULL;
		return fa -> LChild;
	}
}

BTree parent_point(BTree T,DataType d) //取得二叉树T 中,数据为d 的节点的父亲, 返回父亲节点的数据。
{
	BTree fa = NULL, cur = T;
	while(cur != NULL && cur -> data != d) {
		if(d > cur -> data) {
			fa = cur;
			cur = cur -> RChild;
		}else{
			fa = cur;
			cur = cur -> LChild;
		}
	}
	if(fa == NULL) return NULL;
	else return fa;
}

BTNode *remov(BTree *T,DataType d) //在二叉树T 中,移除一个数据为d 的节点, 返回被移除节点的原来位址。
{
	BTNode *parent = parent_point(*T, d); //找到待删节点的父节点
    BTNode *node = search(*T, d); //找到待删节点
    if(node == NULL) //待删节点不存在
        printf("没有待删节点\n");
    else //待删节点存在
    {
        if(node->LChild == NULL && node->RChild == NULL) //如果待删节点是叶子节点
        {
           // assert(parent != NULL);
            if(parent == NULL) //如果是根节点
                *T = NULL;
            else //其他节点
            {
                if(node == parent->LChild)
                    parent->LChild = NULL;
                else
                    parent->RChild = NULL;
            }
        }
        else if(node->RChild == NULL) //如果待删节点只有左子树节点
        {
            if(parent == NULL) //如果是根节点
                *T = node->LChild;
            else //其他节点
            {
                if(node == parent->LChild)
                    parent->LChild = node->LChild;
                else
                    parent->RChild = node->LChild;
            }
        }
        else if(node->LChild == NULL) //如果待删节点只有右子树节点
        {
            if(parent == NULL) //如果是根节点
                *T = node->RChild;
            else //其他节点
            {
                if(node == parent->LChild)
                    parent->LChild = node->RChild;
                else
                    parent->RChild = node->RChild;
            }
        }
        else //如果带删节点左右子树节点都存在
        {
            BTNode *new_node = node->RChild; //需要找到右子树的最左那个
            BTNode *new_node_parent = NULL;
            while(new_node->LChild != NULL)
            {
                new_node_parent = new_node;
                new_node = new_node->LChild;
            }

            //先将后续节点的左右儿子设置好
            new_node->LChild = node->LChild;
            if(new_node != node->RChild)
                new_node->RChild = node->RChild;

            //设置后续节点的父亲
            if(parent == NULL)
                *T = new_node;
            else
            {
                if(node == parent->LChild) //如果带删节点是父节点的左节点
                    parent->LChild = new_node;
                else //如果待删节点是父节点的右节点
                    parent->RChild = new_node;
            }

            //删除后续节点
            if(new_node_parent != NULL)//将原来的右子树最左节点删掉
                new_node_parent->LChild = NULL;
        }
    }
    return node;
}
DataType parent(BTree T,DataType d) //取得二叉树T 中,数据为d 的节点的父亲, 返回父亲节点的数据。
{
	BTree fa = NULL, cur = T;
	while(cur != NULL && cur -> data != d) {
		if(d > cur -> data) {
			fa = cur;
			cur = cur -> RChild;
		}else{
			fa = cur;
			cur = cur -> LChild;
		}
	}
	if(fa == NULL) return -1;
	else return fa -> data;
}
DataType leftSon(BTree T,DataType d) //取得二叉树T 中,数据为d 的节点的左子树, 返回左子树根节点的数据。
{
	BTNode *pos = search(T, d);
	if(pos == NULL) return -1;
	else return pos -> LChild == NULL ? -1: pos -> LChild -> data;
}
DataType rightSon(BTree T,DataType d) //取得二叉树T 中,数据为d 的节点的右子树,返回右子树根节点的数据。
{
	BTNode *pos = search(T, d);
	if(pos == NULL) return -1;
	else return pos -> RChild == NULL ? -1: pos -> RChild -> data;
}
int depth(BTree T, DataType d) //返回二叉树T 中,数据为d 的节点的深度。
{
	if(T == NULL) return 0;
	if(d > T -> data) {
		return 1 + depth(T -> RChild, d);
	}else if(d == T -> data) {
		return 1;
	}else{
		return 1 + depth(T -> LChild, d);
	}
}
int height(BTree T) //返回二叉树T 的深度,即所有节点的最大深度。
{
	if(T == NULL) return 0;
	if(T -> LChild == NULL && T -> RChild == NULL) return 1;
	int Ld = height(T -> LChild), Rd = height(T -> RChild);
	return 1 + (Ld > Rd ? Ld : Rd);
}
int isLeaf(BTree T,DataType d) //对于二叉树T,判断数据为d 节点是否为叶节点。
{
	BTNode *pos = search(T, d);
	return (pos -> LChild == NULL && pos -> RChild == NULL) ? 1 : 0;
}
int leafCount(BTree T) //返回二叉树T 的叶节点个数。
{
	if(T == NULL) return 0;  //空树
	if(T -> LChild == NULL && T -> RChild == NULL) return 1;
	return leafCount(T -> LChild) + leafCount(T -> RChild);
}

int print_cousin(BTree T, int fad,int depd, int fa, int h) {

	if(h == depd && fa != fad) {
		printf("%d ",T -> data);
		return 1;
	}
	int L = 0, R = 0;
	if(T -> LChild != NULL) L = print_cousin(T -> LChild, fad, depd, T -> data, h+1);
	if(T -> RChild != NULL) R = print_cousin(T -> RChild, fad, depd, T -> data, h+1);
	return L + R;
}

int allCousins(BTree T,DataType d) //对于二叉树T,打印所有数据为d 节点的堂兄弟,返回堂兄弟节点的个数。
{
	if(T == NULL) return 0;
	int depd = depth(T, d);
	int fad = parent(T, d);
	return print_cousin(T, fad, depd, -1, 1);
}
void clearTree(BTree *T) //清除二叉树T。
{
	if(T == NULL) return;
	clearTree(&((*T) -> LChild));
	clearTree(&((*T) -> RChild));
	free(*T);
	*T = NULL;
}

void mid_visit(BTree T, int d) {
	int i;
	if(T == NULL) return;
	if(T -> RChild != NULL) mid_visit(T -> RChild, d+1);
	for(i = 1; i <= d; i++) printf(" ");
	printf("%d", T -> data);
	if(T -> LChild != NULL) mid_visit(T -> LChild, d+1);
}

void printTree(BTree T) //自上而下打印二叉树T,顺序为右子树、根节点、然后左子树;深度相同的节点数据之前要有相同个数的空格。
{
	mid_visit(T, 1);
}
void preorderTraversal(BTree T) //使用前序遍历打印二叉树所有节点的数据。
{
	if(T == NULL) return;
	printf("%d ",T -> data);
	if(T -> LChild != NULL) preorderTraversal(T -> LChild);
	if(T -> RChild != NULL) preorderTraversal(T -> RChild); 
}
void inorderTraversal(BTree T) //使用中序遍历打印二叉树所有节点的数据。
{
	if(T == NULL) return;
	if(T -> LChild != NULL) inorderTraversal(T -> LChild);
	printf("%d ",T -> data);
	if(T -> RChild != NULL) inorderTraversal(T -> RChild); 
}
void postorderTraversal(BTree T) //使用后序遍历打印二叉树所有节点的数据。
{
	if(T == NULL) return;
	if(T -> LChild != NULL) postorderTraversal(T -> LChild);
	if(T -> RChild != NULL) postorderTraversal(T -> RChild); 
	printf("%d ",T -> data);
}

void mid(BTree T, int *index, BTNode arr[]) {
	if(T == NULL) return;
	if(T -> LChild != NULL) mid(T -> LChild, index, arr);
	*index = *index + 1;
	arr[*index] = *T;
	if(T -> RChild != NULL) mid(T -> RChild, index, arr);
}

int num_node(BTree T) {  //返回二叉树节点个数
	if(T == NULL) return 0;
	return 1 + num_node(T -> LChild) + num_node(T -> RChild);
}

void fill(BTree T, DataType all[], int *index) {  //辅助函数,填充数据
	if(T -> LChild != NULL) fill(T -> LChild, all, index);

	*index = *index + 1;
	T -> data = all[*index];
	if(T -> RChild != NULL) fill(T -> RChild, all, index);
}

BTree toCompletTree(BTree T) //将二叉树T 转换成完全二叉树,返回完全二叉树。
{
	int n = num_node(T), index = 0, i;
	BTNode * arr = (BTNode *) malloc((n+1) * sizeof(BTNode));
	DataType *v = (DataType *)malloc((n+1) * sizeof(DataType));
	mid(T, &index, arr);
	for(int i=1;i<=index;i++) v[i] = arr[i].data;
	for(i = 1; i <= n; i++) {
		if(2 * i <= n) arr[i].LChild = &arr[2*i];
		else arr[i].LChild = NULL;

		if(2 * i + 1 <= n) arr[i].RChild = &arr[2*i+1];
		else arr[i].RChild = NULL;
	}
	index = 0;
	fill(arr + 1, v, &index);
	return arr + 1;
}

int is_same(BTree S, BTree T)   //检查二叉树S与二叉树T是否相同
{
	if((S == NULL && T != NULL) || (S != NULL && T == NULL)) return 0;
	if(S == NULL && T == NULL) return 1;
	if(S -> data != T -> data) return 0;
	return is_same(S -> LChild, T -> LChild) && is_same(S -> RChild, T -> RChild) ? 1 : 0;
}
int isSubtree(BTree S, BTree T) //检查二叉树S 是否为二叉树T 的子树。
{
	return (is_same(S, T->LChild) || is_same(S, T -> RChild)) ? 1 : 0;
}

int check(BTree S, BTree T) 
{
	if(S == NULL && T == NULL) return 1;
	if(S == NULL || T == NULL) return 0;
	int L = check(S -> LChild, T-> RChild), R = check(S -> RChild, T -> LChild);
	return (L == 1 && R == 1) ? 1 : 0;
}

int isSymmetric(BTree T) //检查二叉树T 是否为对称树。一棵对称的二叉树是以通过根节点的垂直线为中心,两边互为镜射的树;以下为左右对称二叉树的例子。
{
	if(T == NULL) return 1;
	return check(T -> LChild, T -> RChild);
}

你可能感兴趣的:(二叉树,c语言)