上一篇文章中给出了用二叉树实现对单词的排序,它区别于更早之前编写的对单词的一般排序方法,在单词乱序的情况下,排序效率还是比较高的。这次笔者又学习了二叉树的一些新的操作,代码如下:
/* 二叉树的一系列基本操作 */
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);
}
}