二叉树的相关操作(C语言)

上一篇文章中给出了用二叉树实现对单词的排序,它区别于更早之前编写的对单词的一般排序方法,在单词乱序的情况下,排序效率还是比较高的。这次笔者又学习了二叉树的一些新的操作,代码如下:

/* 二叉树的一系列基本操作 */

typedef struct TreeNote {
	char c;
	struct TreeNote *left;
	struct TreeNote *right;
	int Ltag;                           /* 用于线索二叉树 */
	int Rtag;
} TreeNote;

#include <stdio.h>
#include <stdlib.h>

TreeNote *talloc(void);
void Create_BTree(TreeNote *&p);
void MidTravel_BTree(TreeNote *p);
int depth(TreeNote *p);
int NoteCount(TreeNote *p);
void CopyTree(TreeNote *p, TreeNote *&newp);
//void Mid_Threading(TreeNote *p, TreeNote *&head);       /* 中序线索化 */
TreeNote *Mid_Threading(TreeNote *p);
void Mid_Thread(TreeNote *&p);                
void Mid_Thread_Tree_Travel(TreeNote *head);

int main()
{
	TreeNote *heading;
	TreeNote *root = NULL;
	TreeNote *newroot = NULL;
	Create_BTree(root);
	MidTravel_BTree(root);               /* 中序遍历二叉树 */
	heading = Mid_Threading(root);        /* 中序线索化 Mid_Threading(root, head); */
	printf("\n");
	MidTravel_BTree(heading);               /* 中序遍历二叉树 */
//	MidTravel_BTree(head);               /* 中序遍历线索二叉树 */
	getchar();
	return 0;
}

/*
 *      分配内存
 */
TreeNote *talloc(void)
{
	TreeNote *p;
	p = (TreeNote *)(malloc(sizeof(TreeNote)));
	if(p == NULL) {
		printf("Out of space");
		return NULL;
	}
	return p;
}

/*
 *      先序建立二叉树
 */
void Create_BTree(TreeNote *&p)         /*传递的参数为 指向指针的引用(指针的别名),修改此引用不仅可以修改被引用的指针,而且可以求改被引用指针指向的内容 */
{
	char a, tmp;
	scanf("%c", &a);
	tmp = getchar();
	if('0' == a)
		p = NULL;
	else {
		p = talloc();
		p->c = a;
		printf("Enter %c left note : ", a);
		Create_BTree(p->left);
		printf("Enter %c right note : ",a);
		Create_BTree(p->right);
	}
}

/*
 *      中序遍历二叉树
 */
void MidTravel_BTree(TreeNote *p)
{
	if(p == NULL)
	return;
	else {
		MidTravel_BTree(p->left);
		printf("%c", p->c);  //printf("%c %d %d", p->c,p->Ltag, p->Rtag);
		MidTravel_BTree(p->right);
	}
}

/*
 *      以节点 p 为根的中序线索化
 */
TreeNote *pre;                          /* 全局变量,指向前一个节点 TreeNote *pre = talloc(); 好像可以不分配内存空间 */
                                        //pre->right = NULL;                              为什么不能放在外面  ?????? 
void Mid_Thread(TreeNote *&p)
{
	if(p) {
		Mid_Thread(p->left);           /* 左子树线索化 */
		if(p->left == NULL) {          /* p在后面,找它的前驱 */
			p->Ltag = 1;
			p->left = pre;
		}
		else 
			p->Ltag = 0;
		if(pre->right == NULL) {       /* pre在前面,找它的后继 */
			pre->Rtag = 1;
			pre->right = p;
		}
		else 
			p->Rtag = 0;
		pre = p;
		Mid_Thread(p->right);          /* 右子树线索化 */
	}
}

/*
 *      带头节点中序线索化
 */
TreeNote *Mid_Threading(TreeNote *p)
{
	TreeNote *head;
//	pre->right = NULL;                            /* 便于在树的最左点开始建线索 */
	head = talloc();
	head->Ltag = 0;                   /* 头节点有左孩子 */
	head->Rtag = 1;                   /* 头节点右指针为右线索,指向后继 */
	head->right = head;               /* 头节点右指针指向自己 */
	pre = head;
	if(NULL == p) {
		head->left = head;
//		return;
	} else {
		head->left = p;
		pre = head;
		Mid_Thread(p);                /* 函数结束后pre指向树的最右端的节点 */
		pre->Rtag = 1;                /* pre 的右指针线索化 */
		pre->right = head;            /* pre 的右指针指向后继head */
		head->right = pre;            /* head 的有指针(已经线索化了)指向树的最右边的节点 */
	}
	return head;
}

/*
 *      遍历中序线索二叉树
 */
void Mid_Thread_Tree_Travel(TreeNote *head)         /* head 为头结点的地址 */
{
	TreeNote *p;
	p = head->left;                                 /* p 指向根节点 */
	while (p != head) {
		while (p->Rtag == 0)
			p = p->left;
		printf("%c", p->c);
		while (p->Rtag == 1 && p->right != head) {
			p = p->right;
			printf("%c",p->c);
		}
		p = p->right;
	}
}

/*
 *      计算二叉树的深度
 */
int depth(TreeNote *p)
{
	int a, b;
	if(NULL == p)
		return 0;
	else {
		a = depth(p->left);
		b = depth(p->right);
		return a>b ? a+1 : b+1;              /*如果不加1,返回值一定为0,因为没有对对深度进行计数 */
	}                                        /* + 1 的作用是,每递归一层说明树的深度 +1 */
}

/*
 *      计算二叉树的节点个数
 */
int NoteCount(TreeNote *p)
{
	if(NULL == p)
		return 0;
	else
		return (NoteCount(p->left) + NoteCount(p->right)) +1;
}

/*
 *      先序复制二叉树
 */
void CopyTree(TreeNote *p, TreeNote *&newp)
{
	if(NULL == p) {
		newp = NULL;
		return;
	} else {
		newp = talloc();
		newp->c = p->c;
		CopyTree(p->left, newp->left);
		CopyTree(p->right, newp->right);
	}
}


### 二叉树的概念 二叉树是一种重要的非线性数据结构,其中每个节点最多有两个子节点:左子节点和右子节点。这种特性使得二叉树非常适合用于表示层次关系,并且可以高效地执行插入、删除和查找操作。 #### 特殊类型的二叉树 - **满二叉树**:除了最后一层外,每一层上的所有节点都有两个子节点。 - **完全二叉树**:除最后一层外,其他各层的节点数都达到最大值;并且最下面一层的节点全部集中在该层最左边的位置上。 - **平衡二叉树**:对于任意节点而言,其左右子的高度差不超过1[^3]。 ### C语言中的二叉树定义 在C语言中,通常通过结构体来定义二叉树节点: ```c typedef struct TreeNode { char data; struct TreeNode* lchild; struct TreeNode* rchild; } BiTree, *BiTreeNode; ``` 这段代码声明了一个名为`TreeNode`的结构体类型,它包含了三个成员变量:存储节点值的`data`字段以及指向左右孩子的指针`lchild`和`rchild`。 ### 使用先序遍历来创建二叉树 给定一个字符串序列作为输入,可以通过递归的方式按照先序方式构建一棵二叉树。当遇到特定字符(如'#')时表示当前分支为空,则返回NULL终止此路径下的进一步处理。 ```c #include <stdio.h> #include <stdlib.h> // 定义二叉树节点结构 typedef struct TreeNode { char data; struct TreeNode* lchild; struct TreeNode* rchild; } BiTree; // 创建新节点函数 BiTree* CreateNode(char val) { BiTree* newNode = (BiTree*)malloc(sizeof(BiTree)); if (!newNode) exit(-1); newNode->data = val; newNode->lchild = newNode->rchild = NULL; return newNode; } // 先序创建二叉树 BiTree* CreateBiTree() { printf("Please input node element, and '#' == 'NULL': "); getchar(); char ch; scanf("%c", &ch); if (ch == '#') return NULL; BiTree* T = CreateNode(ch); T->lchild = CreateBiTree(); // 左子 T->rchild = CreateBiTree(); // 右子 return T; } ``` 上述程序实现了基于用户交互式的二叉树构造过程,在实际应用中可以根据具体需求调整读取逻辑以适应不同的应用场景[^2]。 ### 层次遍历算法 为了能够逐层访问整棵二叉树并打印出各个节点的信息,这里提供了一种利用队列辅助完成的方法——广度优先搜索(BFS),即所谓的“按层遍历”。 ```c void LevelOrderTraversal(BiTree* root) { if (!root) return; BiTree* queue[100]; // 假设最大深度不会超过100 int front = 0, rear = 0; queue[rear++] = root; while(front != rear){ BiTree* current = queue[front++]; printf("%c ", current->data); if(current->lchild!=NULL) queue[rear++]=current->lchild; if(current->rchild!=NULL) queue[rear++]=current->rchild; } } ``` 在这个例子中,使用数组模拟了FIFO行为的简单队列机制来进行节点间的传递工作[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值