- OS: Mac Catalina 10.15.4
- Hardware: Intel Core i9/16G 2667MHz DDR4
- 编译器版本:Mac Xcode 11.6
第05章 树和二叉树
目录
5.2.2 按完全二叉树的层次顺序依次输入结点信息建立二叉链表的算法
5.2.5.3 例题3 在二叉树中查询结点并计算二叉结点的层次
5.1 二叉树
5.1.1 二叉树的链式存储结构
typedef char DataType; // 使用char来代表数据类型
typedef struct node
{
DataType data;
struct node *lchild, *rchild;
}BinTNode;
typedef BinTNode *BinTree;
5.2 二叉树运算
5.2.1 按广义表表示二叉树结构生成二叉链表的算法
// 按广义表表示二叉树结构生成二叉链表的算法
// 参数:
// char *str str为存储广义表的字符串的指针
// 返回:
// BinTNode * 指向二叉树的指针
BinTNode *CreateTree(char *str)
{
BinTNode *St[100]; // 用指针数组模拟栈
BinTNode *p = NULL;
int top, k = 0, j = 0;
top = -1; // 置空栈
char ch = str[j];
BinTNode *b = NULL;
while (ch != '\0')
{
switch (ch)
{
case '(':
top++;
St[top] = p;
k = 1;
break;
case ')':
top--;
break;
case ',':
k = 2;
break;
default:
p = (BinTNode *)malloc(sizeof(BinTNode));
p->data = ch;
p->lchild = p->rchild = NULL;
if (b == NULL)
b = p;
else
{
switch(k)
{
case 1:
St[top]->lchild = p;
break;
case 2:
St[top]->rchild = p;
break;
}
}
}
j++;
ch = str[j];
}
return b;
}
int main(void)
{
char *str = "(A(B(,D(E,F)),C)";
BinTNode *bt = CreateTree(str);
Postorder(bt);
printf("\nDone.\n");
return 0;
}
5.2.2 按完全二叉树的层次顺序依次输入结点信息建立二叉链表的算法
// 按完全二叉树的层次顺序依次输入结点信息建立二叉链表
// Q[1..n]是一个BinTNode类型的指针数组,front和rear分别是队头和队尾指针
// 参数:
// BinTree bt 完全二叉树
// 返回:
// BinTree 建立后的二叉链表
// 程序:
// 喻晓良
// 修改记录:
// 2022-03-12
//-----------------------------------------------------------
BinTree CreateBinTree(BinTree bt)
{
BinTNode *Q[100]; // 定义队列
BinTNode *s;
int front, rear;
char ch;
ch = getchar();
bt = NULL; // 置空二叉树
front = 1; rear = 0; // 初始化队列
while (ch != '#') // 假设结点值为单字符,#为终止符号
{
s = NULL;
if (ch != '@')
{
s = (BinTNode *)malloc(sizeof(BinTNode)); // 申请结点
s->data = ch; s->lchild = s->rchild = NULL; // 新结点赋值
}//endif_1
rear++; // 队尾指针自增
Q[rear] = s; // 将新结点地址或虚结点地址(NULL)入队
if (rear == 1) // 若rear为1,则说明是根结点,用bt指向它
bt = s;
else
{
if (s != NULL && Q[front] != NULL) // 当前结点及其双亲结点都不是虚结点
{
if (rear % 2 == 0) // rear为偶数,新结点应作为左孩子
Q[front]->lchild = s;
else
Q[front]->rchild = s; // rear为奇数,新结点应作为右孩子
}
if (rear % 2 != 0)
front++; // rear为奇数,front指向下一个双亲
}
ch = getchar(); // 读下一个结点值
} //end while
return bt;
}
程序示例:
int main(void)
{
BinTree bt = NULL;
printf("输入完全二叉树,@表示虚结点,#表示输入完毕:\n");
bt = CreateBinTree(bt);
Postorder(bt);
printf("\n完成.\n");
return 0;
}
5.2.3 二叉树的递归遍历算法
5.2.3.1 前序遍历二叉树算法
// 前序遍历二叉树算法
// 参数:
// BinTree bt 采用二叉树链表存储结构,并设结点值为字符型
// 返回:
// void
void Preorder(BinTree bt)
{
if (bt != NULL)
{
printf("%c", bt->data); // 访问根结点
Preorder(bt->lchild); // 前序遍历左子树
Preorder(bt->rchild); // 前序遍历右子树
}
}
5.2.3.2 中序遍历二叉树算法
// 中序遍历二叉树算法
// 参数:
// BinTree bt 采用二叉树链表存储结构,并设结点值为字符型
// 返回:
// void
void Inorder(BinTree bt)
{
if (bt != NULL)
{
Inorder(bt->lchild); // 中序遍历左子树
printf("%c", bt->data); // 访问根结点
Inorder(bt->rchild); // 中序遍历右子树
}
}
5.2.3.3 后序遍历二叉树算法
// 后序遍历二叉树算法
// 参数:
// BinTree bt 采用二叉树链表存储结构,并设结点值为字符型
// 返回:
// void
void Postorder(BinTree bt)
{
if (bt != NULL)
{
Postorder(bt->lchild); // 后序遍历左子树
Postorder(bt->rchild); // 后序遍历右子树
printf("%c", bt->data); // 访问结点
}
}
5.2.3.4 二叉树递归便利示例
int main(void)
{
BinTree bt = NULL;
printf("使用完全二叉树构建,@表示虚结点,#结束输入:\n");
bt = CreateBinTree(bt);
printf("前序输出二叉树:"); Preorder(bt);
printf("\n中序输出二叉树:"); Inorder(bt);
printf("\n后序输出二叉树:"); Postorder(bt);
printf("\n");
return 0;
}
5.2.4 二叉树的非递归遍历算法
5.2.4.1 利用栈的非递归中序遍历算法
// 利用栈的非递归中序遍历算法
// 参数:
// BinTree bt 采用二叉树链表存储结构,并设结点值为字符型
// 返回:
// void
void Inorder1(BinTree bt)
{
SeqStack S;
BinTNode *p;
InitStack(&S);
printf("入栈根结点: %c(%p)\n", bt->data, bt);
Push(&S, bt);
while (!IsStackEmpty(&S))
{
while (GetTop(&S))
{
printf("入栈左子树地址: %p, 值: %c\n", GetTop(&S)->lchild
, ((GetTop(&S)->lchild != NULL) ? GetTop(&S)->lchild->data : ' ')
);
Push(&S, GetTop(&S)->lchild); // 直到左子树空为止
}
printf("最上面一个空地址退栈\n");
p = Pop(&S); // 空指针退栈
if (!IsStackEmpty(&S))
{
printf("结点【%c】\n", GetTop(&S)->data); // 访问根结点
printf("退栈地址: %p, 值: %c\n", GetTop(&S)
, ((GetTop(&S) != NULL) ? GetTop(&S)->data : ' ')
);
p = Pop(&S);
printf("右子树入栈地址: %p, 值: %c\n", p->rchild
, ((p->rchild != NULL) ? p->rchild->data : ' ')
);
Push(&S, p->rchild); // 右子树进栈
}
}
}
程序范例:
#include <stdio.h>
#include "SeqStack.h"
#include "BinTNode.h"
int main(void)
{
BinTree bt = NULL;
printf("使用完全二叉树构建,@表示虚结点,#结束输入:\n");
bt = CreateBinTree(bt);
printf("中序非递归遍历输出二叉树:"); Inorder1(bt);
printf("\n");
return 0;
}
5.2.4.2 利用栈的非递归中序遍历算法(指针数组版)
// 非递归中序遍历算法(指针数组版)
// 参数:
// BinTree bt 采用二叉树链表存储结构,并设结点值为字符型
// 返回:
// void
void Inorder2(BinTree bt)
{
BinTNode *ST[100]; // 用指针数组模拟栈
int top = 0; // 初始化数组
ST[top] = bt;
do
{
while (ST[top] != NULL) // 根结点及其所有的左结点地址装入数组
{
top = top + 1;
ST[top] = ST[top - 1]->lchild;
}
top = top - 1;
if (top >= 0) // 判断数组中地址是否访问完
{
printf("%c", ST[top]->data); // 访问结点
ST[top] = ST[top]->rchild; // 扫描右子树
}
}while (top != -1);
}
程序示例:
#include <stdio.h>
#include "SeqStack.h"
#include "BinTNode.h"
int main(void)
{
BinTree bt = NULL;
printf("使用完全二叉树构建,@表示虚结点,#结束输入:\n");
bt = CreateBinTree(bt);
printf("中序非递归遍历输出二叉树:"); Inorder2(bt);
printf("\n");
return 0;
}
5.2.4.3 利用栈的非递归前序遍历算法
// 非递归前序遍历算法(栈方法)
// 参数:
// BinTree bt 采用二叉树链表存储结构,并设结点值为字符型
// 返回:
// void
void Preorder1(BinTree bt)
{
SeqStack S;
InitStack(&S); // 初始化栈
Push(&S, bt); // 根结点指针进栈
while (!IsStackEmpty(&S))
{
bt = Pop(&S); // 出栈
if (bt != NULL)
{
printf("%c", bt->data); // 访问结点,假设数据域为字符型
Push(&S, bt->rchild); // 右子树入栈
Push(&S, bt->lchild); // 左子树入栈
}
}
}
程序范例:
#include <stdio.h>
#include "SeqStack.h"
#include "BinTNode.h"
int main(void)
{
BinTree bt = NULL;
printf("使用完全二叉树构建,@表示虚结点,#结束输入:\n");
bt = CreateBinTree(bt);
printf("前序非递归遍历输出二叉树:"); Preorder1(bt);
printf("\n");
return 0;
}
5.2.4.4 非递归的按层遍历二叉链表树
// 非递归按层遍历二叉链表树
// 按层遍历二叉树,从上到下,从左到右
// 参数:
// BinTree bt 采用二叉树链表存储结构,并设结点值为字符型
void TransLevel(BinTree bt)
{
CirQueue Q;
InitQueue(&Q); // 初始化队列为空队列
if (bt == NULL)
return; // 二叉树为空,返回
else
{
printf("%c", bt->data); // 输出根结点,假设其数据域为字符型
EnQueue(&Q, bt); // 根结点入队
while (!IsQueueEmpty(&Q))
{
bt = ExQueue(&Q); // 出队列
if (bt->lchild != NULL)
{
printf("%c", bt->lchild->data); // 输出左子树根结点
EnQueue(&Q, bt->lchild); // 左子树入队列
}
if (bt->rchild != NULL)
{
printf("%c", bt->rchild->data); // 输出右子树根结点
EnQueue(&Q, bt->rchild); // 右子树入队列
}
} // end of the while
} // end of the if
}
程序范例:
#include <stdio.h>
#include "SeqStack.h"
#include "CirQueue.h"
#include "BinTNode.h"
int main(void)
{
BinTree bt = NULL;
printf("使用完全二叉树构建,@表示虚结点,#结束输入:\n");
bt = CreateBinTree(bt);
printf("非递归按层遍历输出二叉树:"); TransLevel(bt);
printf("\n");
return 0;
}
5.2.5 综合例题
5.2.5.1 例题1 前序、中序、后续输出二叉树
分别写出如图5.12所示的二叉树的前、中、后序遍历序列。
#include <stdio.h>
#include "SeqStack.h"
#include "CirQueue.h"
int main(void)
{
BinTree bt = NULL;
printf("使用完全二叉树构建,@表示虚结点,#结束输入:\n");
bt = CreateBinTree(bt);
printf("非递归栈方式, 前序遍历二叉树:"); Preorder1(bt);
printf("\n非递归栈方式, 中序遍历二叉树:"); Inorder1(bt);
printf("\n递归栈方式, 后序遍历二叉树:"); Postorder(bt);
printf("\n");
return 0;
}
5.2.5.2 例题2 求二叉树深度
// 求二叉树深度的递归算法
// 若一棵二叉树为空,则它的深度为0,否则它的深度等于其左右子树中的最大深度+1
// 参数:
// BinTree bt 采用二叉树链表存储结构,并设结点值为字符型
// 返回:
// void
int BinTreeDepth(BinTree bt)
{
int depl, depr;
if (bt == NULL)
return 0; // 对于空树,返回0,结束递归
else
{
depl = BinTreeDepth(bt->lchild); // 计算左子树的深度
depr = BinTreeDepth(bt->rchild); // 计算右子树的深度
if (depl > depr)
return depl + 1;
else
return depr + 1;
}
}
示例:
#include <stdio.h>
#include "BinTNode.h"
int main(void)
{
BinTree bt = NULL;
printf("使用完全二叉树构建,@表示虚结点,#结束输入:\n");
bt = CreateBinTree(bt);
printf("二叉树深度为:%d\n", BinTreeDepth(bt));
return 0;
}
5.2.5.3 例题3 在二叉树中查询结点并计算二叉结点的层次
// 在二叉树中查找值为x的结点(前序遍历法)
// 参数:
// BinTree bt 采用二叉树链表存储结构,并设结点值为字符型
// DataType x 值为x
// 返回:
// bool 找到返回true,否则返回false
extern BinTNode *pNodeDomain;
bool FindBT(BinTree bt, DataType x)
{
static bool found = false;
if ((bt != NULL) && (!found))
{
if (bt->data == x)
{
pNodeDomain = bt;
found = true;
}
else
{
FindBT(bt->lchild, x); // 遍历查找左子树
FindBT(bt->rchild, x); // 遍历查找右子树
}
}
return found;
}
// 求结点的层次
// 参数:
// BinTree bt 采用二叉树链表存储结构,并设结点值为字符型
// BinTNode *p 要找到的结点
// int lh 当前查找在第几层,初始调用从1开始
// 返回:
// int 节点所在层次
int level(BinTree bt, BinTNode *p, int lh)
{
static int h = 0;
if (bt == NULL) h = 0;
else if (bt == p)
h = lh;
else
{
level(bt->lchild, p, lh + 1);
if (h == 0) // 表示左子树已查完
level(bt->rchild, p, lh + 1);
}
return h;
}
程序示例:
#include <stdio.h>
#include "BinTNode.h"
BinTNode *pNodeDomain;
int main(void)
{
BinTree bt = NULL;
char ch;
int lh = 0;
printf("使用完全二叉树构建,@表示虚结点,#结束输入:\n");
bt = CreateBinTree(bt);
//不停地使用getchar()获取缓冲中字符,直到获取的c是“\n”或文件结尾符EOF为止
while ((ch = getchar()) != EOF && ch != '\n');
printf("输入要查找的值:"); scanf("%c", &ch);
if(FindBT(bt, ch))
{
lh = 1;
printf("找到了结点,节点值为:%c,节点的层次为:%d\n",
pNodeDomain->data, level(bt, pNodeDomain, lh));
}
else
printf("没有查询到.\n");
return 0;
}
5.3 线索二叉树
5.3.1 二叉树的线索化
5.3.1.1 二叉链表加中序线索
// 对以根结点指针为bt的二叉链表树加中序线索的算法
// 参数:
// BinThrTree bt 二叉线索根结点
// 返回:
// void
void InorderThread(BinThrTree bt)
{
static BinThrNode *pre = NULL;
if (bt != NULL) // 当二叉树为空时结束递归
{
InorderThread(bt->lchild); // 左子树线索化
if (bt->lchild == NULL)
bt->ltag = 1;
else
bt->ltag = 0;
if (bt->rchild == NULL)
bt->rtag = 1;
else
bt->rtag = 0;
if (pre)
{
if (pre->rtag == 1) // 给前趋结点加后继线索
pre->rchild = bt;
if (bt->ltag == 1) // 给当前结点加前趋线索
bt->lchild = pre;
}
pre = bt; // 将刚访问过的当前结点置为前趋结点
InorderThread(bt->rchild); // 右子树线索化
}
}
程序示例:
#include <stdio.h>
#include "BinThrTree.h"
int main(void)
{
BinThrTree bt = NULL;
printf("使用完全二叉树构建,@表示虚结点,#结束输入:\n");
bt = CreateBinTree(bt);
printf("构造二叉树完成,开始加中序索引...\n");
InorderThread(bt);
printf("中序索引完成,开始输出二叉线索树...\n");
TinorderThrTree(bt);
return 0;
}
代码中使用到5.3.2.1的程序段和5.3.2.2的程序段。见下文。
5.3.2 二叉线索链表上的运算
5.3.2.1 查找某结点*p的后继结点
// 中序线索二叉树上求结点*p的中序后继结点
// 参数:
// BinThrNode *p 节点*p
// 返回:
// BinThrNode 后继结点
BinThrNode *InorderNext(BinThrNode *p)
{
if (p->rtag == 1) // rchild域为右线索
return p->rchild; // 返回中序后继结点指针
else
{
p = p->rchild; // 从*p的右孩子开始
while (p->ltag == 0)
p = p->lchild; // 沿左指针向下查找
return p;
}
}
5.3.2.2 线索二叉树的遍历
// 遍历以bt为根结点指针的中序线索二叉树
// 参数:
// BinThrTree bt 以bt为根结点指针的中序线索二叉树
// 返回:
// void
void TinorderThrTree(BinThrTree bt)
{
BinThrNode *p;
if (bt != NULL) // 二叉树不为空
{
p = bt; // 使p指向根结点
while (p->ltag == 0)
p = p->lchild; // 查找出中序遍历的第一个结点
do
{
printf("[%c <- %d ",
(p->lchild == NULL ? ' ' : p->lchild->data),
p->ltag);
printf("%c", p->data); // 输出访问结点值
printf(" %d -> %c]\n", p->rtag,
(p->rchild == NULL ? ' ' : p->rchild->data));
p = InorderNext(p); // 查找结点*p的中序后继结点
}while (p != NULL); // 当p为空时算法结束
}
}
5.4 数和森林
5.4.1 数的存储结构
5.4.1 双亲表示法
#define MaxTreeSize 100
typedef char DataType;
typedef struct
{
DataType data; // 树结点数据域
int parent; // 双亲位置域
} PTNode;
typedef struct
{
PTNode nodes[MaxTreeSize];
int n; // 结点数
}PTree;
5.4.2 孩子链表表示法
#define MAXTreeSize 100
typedef char DataType;
typedef struct cnode // 孩子链表结点类型
{
int child; // 孩子结点在指针数组中的序号
struct cnode *next;
}CNode;
typedef struct
{
DataType data; // 树中结点数据域
CNode *firstchild; // 孩子结点头指针
}PANode; // 指针数组结点类型
typedef struct
{
PANode nodes[MAXTreeSize]; // 指针数组
int n, r; // n为结点数, r为根结点在指针数组中的位置(即下标)
}CTree;
5.5 哈夫曼树及其应用
5.5.1 最优二叉树(哈夫曼树)
5.5.1.1 哈夫曼树存储结构
#define n 100 // 叶子结点数
#define m 2 * n - 1 // 哈夫曼树中结点总数
typedef struct
{
float weight; // 权值
int lchild, rchild, parent; // 左右孩子及双亲指针
}HTNode; // 树中结点类型
typedef HTNode HuffmanTree[m + 1]; // 0号单元不用
5.5.1.2 选择两个最小权值根结点并返回数组下标
// 在HT[1..k]中选择parent为0且权值最小的两个根结点
// 其序号分别存储在s1和s2指向的对应变量中
// 参数:
// HuffmanTree HT 一维数组形式的哈夫曼树
// int k 数组下标的最大范围
// int *s1 返回的最小值下标
// int *s1 返回的次最小值下标
// 返回:
// void
void SelectMinItem(HuffmanTree HT, int k, int *s1, int *s2)
{
if (k < 2) return;
const float MAX_VALUE = 65535.0;
int i, j;
float min = MAX_VALUE;
// 取最小权值
for (i = 1; i <= k; i++)
{
if (HT[i].weight < min && HT[i].parent == 0)
{
j = i;
min = HT[i].weight;
}
}
*s1 = j;
//取次最小权值
min = MAX_VALUE;
for (i = 1; i <= k; i++)
{
if (HT[i].weight < min && HT[i].parent == 0 && i != *s1)
{
j = i;
min = HT[i].weight;
}
}
*s2 = j;
}
5.5.1.3 构造哈夫曼树算法
// 创建哈夫曼树
// 参数:
// HuffmanTree HT 一维数组形式的哈夫曼树
// 返回:
// void
void CreateHuffmanTree(HuffmanTree HT)
{
int i;
int s1, s2;
for (i = 1; i <= m; i++) // 初始化哈夫曼树
{
HT[i].lchild = 0;
HT[i].rchild = 0;
HT[i].parent = 0;
HT[i].weight = 0;
}
for (i = 1; i <= n; i++) // 输入前n个叶结点的权值
scanf("%f", &HT[i].weight);
for (i = n + 1; i <= m; i++) // 在HT[1..i-1]中选择parent为0且权值最小的两个根结点,序号分别为s1和s2
{
select(HT, i - 1, &s1, &s2);
HT[s1].parent = i;
HT[s2].parent = i;
HT[i].lchild = s1;
HT[i].rchild = s2;
HT[i].weight = HT[s1].weight + HT[s2].weight; // 权值之和
}
}
5.5.1.4 哈夫曼树构造示例
#include <stdio.h>
#include "HuffmanTree.h"
int main(void)
{
HuffmanTree ht;
printf("开始输入8个权值:");
CreateHuffmanTree(ht);
return 0;
}
5.5.2 哈夫曼编码
5.5.2.1 哈夫曼编码字符集存储结构
typedef struct
{
char ch; // 存放编码的字符
char bits[n + 1]; // 存放编码的位串
int len; // 编码长度
}CodeNode;
typedef CodeNode HuffmanCode[n + 1];
5.5.2.2 根据哈夫曼树求哈夫曼编码表
// 依据哈夫曼树HT求哈夫曼编码表
// 参数:
// HuffmanTree HT 一维数组形式的哈夫曼树
// HuffmanCode HC 返回哈夫曼编码表
// 返回:
// void
void HuffmanEncoding(HuffmanTree HT, HuffmanCode HC)
{
int c, p , i; // c和p分别指示HT中孩子和双亲的位置
char cd[n + 1]; // 临时存放编码串
int start; // 指示编码在cd中的起始位置
cd[n] = '\0'; // 最后一位放上串结束符
for (i = 1; i <= n; i++)
{
start = n; // 初始位置
c = i; // 从叶子结点HT[i]开始上溯
HC[i].ch = HT[i].ch; // 复制字符
while ((p = HT[c].parent) > 0) // 直到上溯到ht[c]是树根为止
{
// 若HT[c]是HT[p]的左孩子,则生成代码0,否则生成代码1
cd[--start] = (HT[p].lchild == c) ? '0': '1';
c = p;
} // end of while
strcpy(HC[i].bits, &cd[start]); // 将临时串cd中的编码拷贝到编码表中
HC[i].len = n - start; // 保存编码长度
} // end of for
}
5.5.2.3 哈夫曼编码示例
#include <stdio.h>
#include "HuffmanCode.h"
int main(void)
{
int i, j;
HuffmanTree HT;
HuffmanCode HC;
printf("输入8个字母和对应的权值:\n");
CreateHuffmanTree(HT);
HuffmanEncoding(HT, HC);
printf("输出哈夫曼树的权:\n");
for (int i = 1; i <= m; i++)
printf("%4.0f", HT[i].weight);
printf("\n输出哈夫曼编码表:\n");
for (i = 1; i <= n; i++)
{
printf("字符:%2c 权值:%3.0f 长度:%2d 编码为: ", HC[i].ch, HT[i].weight, HC[i].len);
for (j = 0; j <= n; j++)
{
if(HC[i].bits[j] == '\0') break;
printf("%2c", HC[i].bits[j]);
}
printf("\n");
}
return 0;
}
5.6 编程练习
5.6.1 习题22
以二叉链表作为存储结构,试利用指针数组实现编写非递归的前序遍历二叉树的算法。
// 非递归前序遍历算法(指针数组版)
// 参数:
// BinTree bt 采用二叉树链表存储结构,并设结点值为字符型
// 返回:
// void
void Preorder2(BinTree bt)
{
BinTNode *ST[100]; // 用指针数组模拟栈
int top = 0; // 初始化数组
ST[top] = bt;
do
{
while (ST[top] != NULL) // 根结点及其所有的左结点地址装入数组
{
printf("%c", ST[top]->data); // 访问结点
top = top + 1;
ST[top] = ST[top - 1]->lchild;
}
top = top - 1;
if (top >= 0) // 判断数组中地址是否访问完
{
ST[top] = ST[top]->rchild; // 扫描右子树
}
}while (top != -1);
}
程序示例:
int main(void)
{
BinTree bt = NULL;
printf("使用完全二叉树构建,@表示虚结点,#结束输入:\n");
bt = CreateBinTree(bt);
printf("非递归指针数组方式, 前序遍历二叉树:"); Preorder2(bt);
printf("\n");
return 0;
}
5.6.2 习题23
以二叉链表作为存储结构,其根结点指针为bt,试写从根开始按层遍历二叉树的算法。
此题可使用前文提到的按层输出二叉树函数。
示例程序如下:
int main(void)
{
BinTree bt = NULL;
printf("使用完全二叉树构建,@表示虚结点,#结束输入:\n");
bt = CreateBinTree(bt);
printf("非递归按层遍历输出二叉树:"); TransLevel(bt);
printf("\n");
return 0;
}
5.6.3 习题24
以中序线索二叉树作为存储结构,试写查找某结点*p的中序前缀结点的算法。
// 中序线索二叉树上求结点*p的中序前趋结点
// 参数:
// BinThrNode *p 节点*p
// 返回:
// BinThrNode 后继结点
BinThrNode *InOrderPre(BinThrNode *p)
{
if (p->ltag == 1) // lchild域为左线索
return p->lchild; // 返回中序前趋结点指针
else
{
p = p->lchild; // 从*p的左孩子开始
if(p->rtag == 0) // 如果左孩子存在一个右孙子,则使用右孙子返回
p = p->rchild;
else if(p->ltag == 0) // 没有右孙子则使用左孙子返回
p = p->lchild;
return p;
}
}
程序示例:
#include <stdio.h>
#include "BinThrTree.h"
int main(void)
{
BinThrTree bt = NULL;
printf("使用完全二叉树构建,@表示虚结点,#结束输入:\n");
bt = CreateBinTree(bt);
printf("构造二叉树完成,开始加中序索引...\n");
InorderThread(bt);
printf("中序索引完成,开始输出二叉线索树...\n");
TinorderThrTree(bt);
return 0;
}