王道——数据结构——栈和队列(1)
王道——数据结构——树与二叉树(1)
王道——数据结构——树与二叉树(3)
王道——数据结构——树与二叉树(4)
本文为王道数据结构的第五章——树与二叉树的编程题。
运行软件:vscode
使用c++文件编写
本文所使用的树为《王道——数据结构——树与二叉树(1)》中建立的树
5、已知一棵二叉树按顺序存储结构进行存储,设计一个算法,求编号分别为i和j的两个结点的最近公共祖先结点。 3、编写后序二叉树的非递归算法。 5、假设二叉树采用二叉链表存储结构,设计一个非递归算法求二叉树的高度。 6、设一棵二叉树中各结点的值互不相同,其先序遍历和中序遍历分别存于两个一维数组A[1……n]和B[1……n]中,试编写算法建立该算法的二叉树和二叉链表 7、二叉树按二叉链表形式存储,写一个判别给定的二叉树是否是完全二叉树的算法。 8、假设二叉树采用二叉链表存储结构存储,试设计一个算法,计算一棵给定二叉树的双分支结点个数。 9、设树B是一棵采用链式结构存储的二叉树,编写一个把树B中所有结点的左右孩子进行交换的函数。 10、假设二叉树采用二叉链表存储结构存储,设计一个算法,求先序遍历序列中第k(k>=1 && k<=二叉树中结点个数)
已知顺序结构存储的树的结构,所以父节点为孩子结点下标除2下取整,所以在寻找i和j的两个结点的最近公共祖先结点时,比较i和j,如果i=j:返回i的值,如果i>j:求i的父节点,如果i// 找编号i和j的最近公共祖先 找序号大的父节点
int test1(TreeNode T[MaxSize], int i, int j){
if(T[i].isEmpty != true && T[j].isEmpty != true){
while(i != j){
if(i>j)
i/2; // 找i的父节点
else
j/2; // 找j的父节点
}
return i;
}
return -1;
// 运行代码
// int i, j;
// TreeNode T[MaxSize];
// InitTree(T);
// buildTree(T, 1);
// Preorder(T, 1);
// printf("\n请输入你想查找的两个编号(使用空格分隔):");
// scanf("%d %d", &i, &j);
// i= test1(T, i, j);
// if (i != -1)
// printf("编号%d的结点值为%d", i, T[i].value);
// else
// printf("输入编号错误,为空结点");
}
二、5.3节
王道——数据结构——树与二叉树(1)中已经写过,详情请参考
王道——数据结构——树与二叉树(1)
4、试给出二叉树自上而下、自右向左的层次遍历// 第四题 层次遍历,使用队列实现,先将右孩子压入队中
void test4(){
BiTree T;
InitBiTree(T);
buildTree(T);
LinkQueue S;
InitLinkQueue(S);
EnQueue(S, T);
BiTNode *x;
while(S.front != NULL){
DeQueue(S, x);
visit(x);
if(x->rchild != NULL)
EnQueue(S, x->rchild);
if(x->lchild != NULL)
EnQueue(S, x->lchild);
}
}
// 第五题 使用栈存储树结点,采用深度优先策略,入栈高度加一,出栈高度减一,highest保存当前高度最高值
// 同第三题, 使用栈实现非递归中序遍历
// 好像有bug,还未完善
void test5(){
BiTree T;
InitBiTree(T);
buildTree(T);
LinkStack S;
InitLinkStack(S);
if(T == NULL)
printf("树高度为0\n");
else{
int high = 0, highest = 0;
BiTNode *p = T;
while(p || S != NULL){
if(p){
Push(S, p);
p = p->lchild;
++high;
if(high > highest)
highest = high;
}
else{
Pop(S, p);
if(p->rchild == NULL)
--high;
p = p->rchild;
}
}
printf("树高度:%d ", highest);
}
}
// 第五题——王道书的方法,使用一个指针last指向下一层最左边的元素,如果队首元素等于last,层数加1
// 队尾元素永远是下一层的最后一个元素
// 找树最大宽度
void test5_2(){
BiTree T;
InitBiTree(T);
buildTree(T);
LinkQueue Q;
InitLinkQueue(Q);
if(T == NULL)
printf("书高度:0");
else{
int weigh = 1, weightest = 0;
BiTNode *p, *last = T;
EnQueue(Q, T);
while (Q.front->next != NULL){
DeQueue(Q, p);
++weigh;
if(p->lchild != NULL)
EnQueue(Q, p->lchild);
if(p->rchild != NULL)
EnQueue(Q, p->rchild);
if(p == last && Q.front->next != NULL){
if(weigh > weightest)
weightest = weigh;
weigh = 0;
last = Q.rear->data;
}
}
printf("树最大宽度:%d ", weightest);
}
}
// 第六题,为了之后测试程序,要建立数组A、B
#define MaxSize 20
// 数组结构
typedef struct{
int data[MaxSize];
int len; //记录数组长度
}arr;
// 初始化数组
void Initarr(arr &arry){
arry.len = 0;
}
// 建立二叉链表
BiTNode *arr_tree(arr arr1, arr arr2){
if(arr2.len == 1){
BiTNode *q = (BiTNode *)malloc(sizeof(BiTNode));
q->data.value = arr2.data[0];
q->lchild = NULL;
q->rchild = NULL;
return q;
}
int first;
for (int i = 0; i<arr1.len; i++){
for(first = 0; first<arr2.len; first++){
if(arr1.data[i] == arr2.data[first])
break;
}
if(arr1.data[i] == arr2.data[first])
break;
}
BiTNode *p = (BiTNode *)malloc(sizeof(BiTNode));
p->data.value = arr2.data[first];
arr arr3, arr4;
Initarr(arr3);
Initarr(arr4);
for(int i = 0; i<first; i++){
arr3.data[i] = arr2.data[i];
++arr3.len;
}
int arr2_now = first;
for(int i = 0; i<arr2.len-first-1; i++){
arr4.data[i] = arr2.data[++arr2_now];
++arr4.len;
}
if(arr3.len!=0)
p->lchild = arr_tree(arr1, arr3);
else
p->lchild = NULL;
if(arr4.len != 0)
p->rchild = arr_tree(arr1, arr4);
else
p->rchild = NULL;
return p;
}
// 运行实现
void test6(){
arr arr1,arr2;
Initarr(arr1);
Initarr(arr2);
int x, i = 0;
// 建立A数组
printf("请输入先序序列顺序(9999退出):");
scanf("%d", &x);
while(x != 9999 &&arr1.len < MaxSize){
arr1.data[i++] = x;
++arr1.len;
printf("输入成功,请继续输入(9999退出):");
scanf("%d", &x);
}
// 建立B数组
printf("请输入先中序列顺序(9999退出):");
scanf("%d", &x);
i = 0;
while(x != 9999 &&arr2.len < MaxSize){
arr2.data[i++] = x;
++arr2.len;
printf("输入成功,请继续输入(9999退出):");
scanf("%d", &x);
}
BiTree T;
T = arr_tree(arr1, arr2);
printf("后序遍历结果为:"); // 用后序遍历查看树
PostOrder(T);
}
// 第七题 判别方法——使用层次遍历,当出现一个结点的孩子为空时,后面的结点都不能有孩子
void test7(){
BiTree T;
InitBiTree(T);
buildTree(T);
BiTNode *p;
int arise = 0; // 标记是否出现孩子为空的结点
LinkQueue Q;
InitLinkQueue(Q);
EnQueue(Q, T);
while(Q.front->next != NULL){
DeQueue(Q, p);
if(arise == 0 && p->lchild != NULL) // 前面结点均有左右孩子,并且该结点左孩子不为空
EnQueue(Q, p->lchild);
else if(arise == 1 && p->lchild != NULL) // 已经出现孩子为空的结点,该结点仍有左孩子,所以不是完全二叉树
break;
else // 前面结点均有左右孩子,但是该结点左孩子为空, 标记位改为1
arise = 1 ;
if(arise == 0 && p->rchild != NULL)
EnQueue(Q, p->rchild);
else if(arise ==1 &&p->rchild != NULL)
break;
else
arise = 1;
}
if(Q.front->next != NULL)
printf("不是完全二叉树");
else
printf("是完全二叉树");
}
// 第八题 采用非递归先序遍历,在访问节点时判断是否有左右孩子,如果有,总数加一
void test8(){
BiTree T;
InitBiTree(T);
buildTree(T);
LinkStack S;
InitLinkStack(S);
BiTNode *p = T;
int sum = 0;
while(p || S != NULL){
if(p){
Push(S, p);
if(p->lchild != NULL && p->rchild != NULL)
++sum;
p = p->lchild;
}
else{
Pop(S, p);
p = p->rchild;
}
}
printf("双分支结点个数为:%d", sum);
}
// 第九题 从最上层开始交换左右子树, 使用队列进行层次遍历,出队对结点访问时,交换结点左右孩子顺序,使用中序遍历验证,二者顺序刚好相反
void test9(){
BiTree T;
InitBiTree(T);
buildTree(T);
InOrder(T);
LinkQueue Q;
InitLinkQueue(Q);
EnQueue(Q, T);
BiTNode *temp, *p;
while(Q.front->next != NULL){
DeQueue(Q, p);
temp = p->lchild;
p->lchild = p->rchild;
p->rchild = temp;
if(p->lchild != NULL)
EnQueue(Q, p->lchild);
if(p->rchild != NULL)
EnQueue(Q, p->rchild);
}
printf("\n");
InOrder(T);
}
// 使用先序序列遍历二叉树,对结点访问时计数,当访问到第k个结点时,返回第k个结点的值
void test10(BiTree T, int k, int &sum, int &value){
++sum;
if(sum == k )
value = T->data.value;
if(sum != k && T->lchild != NULL)
test10(T->lchild, k, sum, value);
if(sum != k && T->rchild != NULL)
test10(T->rchild, k, sum, value);
// 运行代码
// BiTree T;
// InitBiTree(T);
// buildTree(T);
// int x, sum = 0, value;
// printf("请输入你想查找的结点位序(从1开始):");
// scanf("%d", &x);
// test10(T, x, sum, value);
// if(sum == x)
// printf("第%d个结点值为:%d", x, value);
// else
// printf("输入位序无效");
}
后续部分留在下一章