二叉树这部分当时学习C语言的时候就没有特别重视,现在遇到这类题就比较头疼,所以需要重新复习一下。
二叉树的建立
广义表方式输出二叉树
二叉树的销毁
求二叉树的深度
二叉树的遍历
统计二叉树的结点数
统计二叉树的叶子结点数
交换左右子树
复制二叉树
查找某一结点
删除二叉树的某一结点
typedef ElemType char; //自定义数据域类型
struct BinaryTree
{
ElemType data; //数据域
struct BinaryTree *lchild; //左子树
struct BinaryTree *rchild; //右子树
};
typedef struct BinaryTree TreeNode; //给结构体struct BinaryTree取个别名叫TreeNode
typedef struct BinaryTree * BiTree; //给结构体指针struct BinaryTree *取个别名叫BiTree
//初始化
void IniBTree(BiTree BT)
{
BT = NULL;
return;
}
/* 先序创建二叉树:根结点 -> 左子树 -> 右子树 */
void CreateBTree(BiTree BT)
{
char ch;
ch = getchar(); //头文件,相当于scanf("%c", &ch)
if (ch == ' ')
BT = NULL;
else
{
if(! (BT = (BiTree)malloc(sizeof(TreeNode))))
exit(1);
BT -> data = ch; //生成根节点
BT -> lchild = NULL; //构造左子树
BT -> rchild = NULL; //构造右子树
CreateBiTree(BT -> lchild);
CreateBiTree(BT -> rchild);
}
}
int StackMaxSize = 3;
void CreateBTreeWithGenList(BiTree BT, char *string)
{
BiTree TempNode;
Bitree s[StackMaxSize]; //定义数组为存储各结点的指针的栈
int top = -1; //栈顶指针,初始值为-1
int branchValue; //分支值,作为处理结点的标志,1表示处理左子树,2表示处理右子树
int i = 0; //数组计数元素
//原二叉树初始化
BT = NULL;
//开始读入广义表字符串
while (string[i])
{
switch(string[i])
{
case ' ': break;
case '(':
{
if (top == StackMaxSize - 1)
{
printf("栈空间太小,需要增大栈空间!\n");
exit(1);
}
top++;
s[top] = TempNode;
k = 1; //切换到左子树
break;
}
case ')':
{
if (top == -1)
{
printf("二叉树广义表字符串错误\n");
exit(1);
}
top--;
}
case ',': k = 2; break; //切换到右子树
default: //默认情况下,即读取到字母字符,对应赋值。
{
TempNode = (BiTree)malloc(sizeof(TreeNode));
TempNode -> data = string[i]; //临时结点赋值
TempNode -> lchild = TempNode -> rchild = NULL;
if (BT == NULL)
BT = TempNode; //根节点赋值
else
{
if (k == 1)
s[top] -> lchild = TempNode;
else
s[top] -> rchild = TempNode;
}
}
} //switch结束
i++;
} //while结束
}
void PrintBTreeWithGenList(BiTree BT)
{
if (BT)
{
printf("%c", BT -> data);
if (BT -> lchild || BT -> rchild)
{
printf("(");
PrintBTreeWithGenList(BT -> lchild);
if (BT -> rchild)
{
printf(",");
PrintBTreeWithGenList(BT -> rchild);
}
printf(")");
}
}
}
void DestroyBTree(BiTree BT)
{
if (BT)
{
DestroyBTree(BT -> lchild);
DestroyBTree(BT -> rchild);
free(BT);
BT == NULL;
}
}
int BTreeEmpty(BiTree BT)
{
if (BT == NULL)
return 1;
else
return 0;
}
//递归方式计算二叉树的深度,每一层的深度都能够得到比较
int BTreeDepth(BiTree BT)
{
if (BT == NULL)
return 0;
else
{
int depth1 = BTreeDepth(BT -> lchild); //计算左子树的深度
int depth2 = BTreeDepth(BT -> rchild); //计算右子树的深度
if (depth1 > depth2)
return depth1 + 1;
else
return depth2 + 1;
}
}
//或递归方式求二叉树的深度
int BTreeDepth(BiTree BT)
{
if (BT == NULL)
return 0;
else
{
int ldepth = BTreeDepth(BT -> lchild);
int rdepth = BTreeDepth(BT -> rchild);
}
return (ldepth > rdepth) ? (ldepth + 1) : (rdepth + 1);
}
/* 前序遍历:根节点 -> 左子树 -> 右子树 */
void PreOrderTraverse(const BiTree BT)
{
if (!BT)
return;
//遍历
printf("%c ", BT -> data); //根节点
PreOrderTraverse(BT -> lchild);
PreOrderTraverse(BT -> rchild);
}
/* 中序遍历:左子树 -> 根节点 -> 右子树 */
void InOrderTraverse(const BiTree BT)
{
if (!BT)
return;
//遍历
InOrderTraverse(BT -> lchild);
printf("%c ", BT -> data); //根节点
InOrderTraverse(BT -> rchild);
}
/* 后序遍历:左子树 -> 右子树 -> 根节点 */
void PostOrderTraverse(const BiTree BT)
{
if (!BT)
return;
//遍历
PostOrderTraverse(BT -> lchild);
PostOrderTraverse(BT -> rchild);
printf("%c ", BT -> data); //根节点
}
/* 层序遍历:逐层从左到右 */
void LevelOrderTraverse(BiTree BT)
{
BiTree temp;
BiTree queue[QueueMaxSize]; //定义队列所使用的数组,元素类型为指向结点的指针类型
int front = 0;
int rear = 0;
if (BT != NULL) //根结点入队
{
queue[rear] = BT;
rear = (rear + 1) % QueueMaxSize;
}
while (front != rear)
{
temp = queue[front];
front = (front + 1) % QueueMaxSize;
printf("%c ", temp -> data);
if (temp -> lchild != NULL) //输出结点存在左子树
{
queue[rear] = temp -> lchild;
rear = (rear + 1) % QueueMaxSize;
}
if (temp -> rchild != NULL)
{
queue[rear] = temp -> rchild;
rear = (rear + 1) % QueueMaxSize;
}
}
}
//1. 层序遍历需要使用一个队列,开始把整个树的根结点入队,然后每从队列中删除一个结点并输出该结点时,都把它的非空的左右孩子入队,当队列为空时算法结束。
//2. 算法中,队列的最大长度不会超过二叉树中相邻的两层的最大结点数,所以提前在程序开始处定义最大队列长度QueueMaxSize大于队列的最大长度,就无需考虑队列溢出的问题了
/* 二叉树的结点数 = 左子树 + 右子树 + 1 */
int BTreeNodeCount(BiTree BT)
{
if (BT == NULL)
return 0;
else
return BTreeNodeCount(BT -> lchild) + BTreeNodeCount(BT -> rchild) + 1;
}
/* 叶子结点:没有左右子树的结点 */
int BTreeLeafCount(BiTree BT)
{
if (BT == NULL)
return 0;
if (BT -> lchild == NULL && BT -> rchild == NULL)
return 1;
//递归实现
return BTreeLeafCount(BT -> lchild) + BTreeLeafCount(BT -> rchlid);
}
/* 统计二叉树的度为1的结点个数 */
//度:一个结点的子结点的个数
int Degree1Count(BiTree BT)
{
if(!BT)
return 0;
if ((!BT -> lchild && BT -> rchild) || (BT -> lchild && !BT -> rchild))
return 1;
else
return Degree1Count(BT -> lchild) + Degree1Count(BT -> rchild);
}
/* 相当于对称翻转,递归实现 */
void ExchangeChildTree(BiTree BT)
{
if (BT)
{
BiTree Temp = NULL;
if (BT -> lchild || BT -> rchild)
{
ExchangeChildTree(BT -> lchild);
ExchangeChildTree(BT -> rchild);
Temp = BT -> lchild;
BT -> lchild = BT -> rchild;
BT -> rchild = Temp;
}
}
}
/* 递归实现 */
BiTree CopyBTree(BiTree BT)
{
BiTree P, lchild, rchild;
if (BT == NULL)
return;
lchild = CopyBTree(BT -> lchild);
rchild = CopyBTree(BT -> rchild);
P = (BiTree)malloc(sizeof(struct BinaryTree));
P -> data = BT -> data;
P -> lchild = lchild;
P -> rchild = rchild;
return P;
}
/* 查找某一结点:查找成功返回结点位置,失败返回NULL */
BiTree* FindBTree(BiTree BT, ElemType x)
{
if (BT == NULL)
return NULL;
else //递归查找
{
if (x == BT -> data)
return BT;
else
{
ElemType* p;
if (p = FindBTree(BT -> lchild, x))
return p;
if (p = FindBTree(BT -> rchild, x))
return p;
return NULL;
}
}
}
//此时的二叉树结构体定义修改为
typedef ElemType char; //自定义数据域类型
struct BinaryTree
{
ElemType data; //数据域
struct BinaryTree *prev; //前驱结点,该指针的目的是为了方便找到父结点
struct BinaryTree *lchild; //左子树
struct BinaryTree *rchild; //右子树
};
typedef struct BinaryTree *BiTree;
//删除某一结点方式:先找到后删除
int DeleteBTreeNode(BiTree BT, ElemType x)
{
//查找到该元素所在的结点位置,返回结点指针!
BiTree temp = FindBTree(BT, x);
if (temp == NULL)
return 0;
//1. 没有子结点
if (temp -> lchild == NULL && temp -> rchild == NULL)
{
if (temp -> prev -> lchild == temp) //如果是父结点的左子树
temp -> prev -> lchild = NULL;
else
temp -> prev -> rchild = NULL;
free(temp);
}
//2. 只有左子树
if (temp -> rchild == NULL)
{
if (temp -> prev -> lchild == temp) //如果是父结点的左子树
temp -> prev -> lchild = temp -> lchild;
else
temp -> prev -> rchild = temp -> lchild;
free (temp);
}
//3. 只有右子树
if (temp -> lchild == NULL)
{
if (temp -> prev -> lchild == temp) //如果是父结点的左子树
temp -> prev -> lchild = temp -> rchild;
else
temp -> prev -> rchild = temp -> rchild;
free (temp);
}
//4. 既有左子树又有右子树
else
{
BiTree y = temp -> rchild; //寻找中序后继结点y,即temp结点右子树的最左子树
while (y -> lchild != NULL)
y = y -> lchild;
if (y == temp -> rchild) //y是要删结点的右子树
{
//判断要删结点是其父结点的左子树还是右子树
if (temp -> prev -> lchild == temp) //左子树
{
temp -> prev -> lchild = y;
y -> lchild = temp -> lchild;
temp -> lchild -> prev = y;
}
else
{
temp -> prev -> rchild = y;
y -> lchild = temp -> lchild;
temp -> lchild -> prev = y;
}
}
else
{
y -> prev -> lchild = y -> rchild; //注意y的右子树可能不存在
//同上。判断要删除结点是其父结点的左子树还是右子树
if (temp -> prev -> lchild == temp) //左子树
{
temp -> prev -> lchild = y;
y -> lchild = temp -> lchild;
y -> rchild = temp -> rchild;
temp -> lchild -> prev = y;
temp -> rchild -> prev = y;
}
else
{
temp -> prev -> rchild = y;
y -> lchild = temp -> lchild;
y -> rchild = temp -> rchild;
temp -> lchild -> prev = y;
temp -> rchild -> prev = y;
}
}
free (temp);
}
return 1;
}
//注:为避免冗长,可将上述判断左右子树及结点替换的部分单独写一个函数实现。
2017.08.20