您的位置:首页 > 理论基础 > 数据结构算法

数据结构——c语言描述 第六章(1)二叉树树的基本操作和二叉树的线索化

2016-07-11 21:48 627 查看
终于到我个人感觉最好玩的一章节,哈哈,个人感觉树和之前的数据结构最重要的区别在于,在这一章当中出现了大量的递归调用,我刚开始也不是很适应,现在基本上也能用得起来递归调用,但是在递归调用中的有时候会出现难以发现的细节,而这些细节往往让程序直接segment fault了,这些细节也只有等着时间的沉淀,代码的积累才会慢慢进步吧。

二叉树的定义:二叉树有一个根节点,根节点下面最多连着两个子二叉树树,可以看见在二叉树的定义当中出现了和广义表一样的特点,就是递归的特性,所以在二叉树的建立,遍历,线索化的过程当中充斥着递归。讲完二叉树的定义之后其实书上写了一大堆关于二叉树的性质的结论和其证明,我在写代码的过程当没用到多少,但是其中有一点比较重要就是如果二叉树有n个节点,那么二叉树的节点的孩子指针当中只有(n+1)个节点指向空指针,这个结论在给二叉树赋值的过程当中和二叉树的线索化过程当中都是有影响的。下面我就把二叉树的代码的写下来,算是对自己学习的一个记录吧。

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

#define TRUE 1
#define FALSE 0;

typedef char Eletype;
typedef struct TreeNode{
struct TreeNode *LChild;
struct TreeNode *RChild;
Eletype data;
}TreeNode;

void creattree (TreeNode **R) ;
void PreOrder (TreeNode *R) ;
int ChangeChildTree (TreeNode *R) ;
int PostTreeDepth (TreeNode *R) ;

int main () {
TreeNode *R;
creattree (&R);
ChangeChildTree (R);
PreOrder (R);
printf ("the tree's depth s %d\n" , PostTreeDepth (R));
}

void creattree (TreeNode **R) {
char c;

if ((c = getchar()) != '.') {
*R = (TreeNode *) malloc (sizeof (TreeNode));
(*R)->data = c;
creattree (&((*R)->LChild));
creattree (&((*R)->RChild));
}else
R = NULL;
}

void PreOrder (TreeNode *R) {
if (R == NULL)
return;
printf ("%c\n" , R->data);
PreOrder (R->LChild);
PreOrder (R->RChild);
}

int PostTreeDepth (TreeNode *R) {
int temp1 = 1;
int temp2 = 1;

if (R == NULL)
return 0;
temp1 += PostTreeDepth (R->LChild);
temp2 += PostTreeDepth (R->RChild);
if (temp1 > temp2)
return temp1;
else
return temp2;
}

int ChangeChildTree (TreeNode *R) {
TreeNode *temp;

if (R == NULL || R->LChild == NULL || R->RChild == NULL)
return FALSE;

temp = R->LChild;
R->LChild = R->RChild;
R->RChild = temp;
return TRUE;
}
这个就是二叉树的基本操作的实现,包括基本的创建二叉树,前序遍历二叉树,交换二叉树的两个子树,求深度等。二叉树的代码都不是很长,但是都包含了递归的特性。

下面的代码是二叉树的前序线索化,书上给出了中序线索化的代码我刚开始傻乎乎的以为和中序遍历转化为前序遍历一样简单,但是事实证明我还是太simple了,仔细分析了线索化的过程后我发现,在递归的过程当中还是有纰漏存在的,改正之后代码的运行正常!

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

typedef char EleType;

typedef struct treenode{
int RTag;
int LTag;
struct treenode *LChild;
struct treenode *RChild;
EleType data;
}TreeNode;

TreeNode *curr;
TreeNode *pre = NULL;

void creattree (TreeNode **R) {
int c;

if ((c = getchar ()) == '.') {
*R = NULL;
return;
}else {
*R = (TreeNode *) malloc (sizeof (TreeNode));
(*R)->data = c;
(*R)->RTag = 0;
(*R)->LTag = 0;
creattree (&(*R)->LChild);
creattree (&(*R)->RChild);
}
}

void preorder (TreeNode *R) {
if (R != NULL) {
printf ("%c " , R->data);
preorder (R->LChild);
preorder (R->RChild);
}
}

void inthreadtree (TreeNode *R) {
if (R != NULL) {
if (R->LChild == NULL) {
R->LTag = 1;
R->LChild = pre;
}
if (pre != NULL && pre->RChild == NULL) {
pre->RTag = 1;
pre->RChild = R;
}
pre = R;
if (R->LTag == 0)
inthreadtree (R->LChild);
if (R->RTag == 0)
inthreadtree (R->RChild);
}
}

int main () {

preorder (node);
printf ("\n");
inthreadtree (node);
}
首先,线索化要求的二叉树的节点结构比普通的二叉树更加复杂一些,包括了两个额外的节点标识符,左节点和右节点标识符。这是用来标志节点的右节点是什么样的类型,是普通的连接,还是经过线索化之后的指针。这个标识符在线索化的过程中也起到了非常大的作用。下面这四行代码应该是突出细节的一个地方,如果没有之前的if判断语句就会在返回上层递归的时候出现原本是指向NULL但是经过线索化后指向前驱或者后继节点的指针进入循环,这也就是为什么如果在这个地方将两个if语句删除会造成segment
fault的原因!
if (R->LTag == 0)
inthreadtree (R->LChild);
if (R->RTag == 0)
inthreadtree (R->RChild);

这里我再上一个二叉树的线索化的插入,书上给出了中序二叉树的插入操作,这里我上一个先序二叉树的插入,不保证正确。。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息