(多考选择题,偶尔涉及树遍历相关的算法题)
typedef struct BTNode
{
ElemType data;
struct BTNode *lchild, *rchild;
}BTNode;
步骤
算法实现
void PreOrder(BTNode *T)
{
if(T != NULL)
{
visit(T);
PreOrder(T->lchild);
PreOrder(T->rchild);
}
}
void PreOrderNonrecursion(BTNode *bt)
{
if(bt != NULL)
{
BTNode *Stack[maxSize]; //定义一个栈
int top = -1; //初始化栈
BTNode *p;
Stack[++top] = bt; //根结点入栈
while(top != -1) //栈空循环退出,遍历结束
{
p = Stack[top--]; //出栈并输出栈顶结点
visit(p);
if(p->rchild != NULL) //右孩子存在,则入栈
Stack[++top] = p->rchild;
if(p->lchild != NULL) //左孩子存在,则入栈
Stack[++top] = p->lchild;
}
}
}
步骤
算法实现
void InOrder(BTNode *T)
{
if(T != NULL)
{
InOrder(T->lchild);
visit(T);
InOrder(T->rchild);
}
}
void InOrderNonrecursion(BTNode *bt)
{
if(bt != NULL)
{
BTNode *Stack[maxSize];
int top = -1;
BTNode *p;
p = bt;
while(top != -1 || p != NULL)
{
while(p !=NULL) //左孩子存在,则入栈
{
Stack[++top] = p;
p = p->lchild;
}
if(top != -1)
{
p = Stack[top--];
visit(p);
p = p->rchild;
}
}
}
}
void PostOrder(BTNode *T)
{
if(T != NULL)
{
PostOrder(T->lchild);
PostOrder(T->rchild);
visit(T);
}
}
void PostOrder(BTNode *T)
{
if(bt != NULL)
{
BTNode *Stack1[maxSize]; int top1 = -1;
BTNode *Stack2[maxSize]; int top2 = -1;
BTNode *p = NULL;
Stack1[++top1] = bt;
while(top1 != -1)
{
p = Stack1[top--];
Stack2[++top2] = p;
if(p->lchild != NULL)
Stack1[++top1] = p->lchild;
if(p->rchild != NULL)
Stack2[++top2] = p->rchild;
}
while(top2 != -1) //出栈序列即为后序遍历序列
{
p = Stack2[top2--];
visit(p);
}
}
}
void level(BTNode *p)
{
int front, rear;
BTNode *que[maxSize]; //定义一个循环队列,用来记录将要访问的层次上的结点
front = rear = 0;
BTNode *q;
if(p != NULL)
{
rear = (rear + 1) % maxSize;
que[rear] = p; //根结点入队
while(front != rear) //队列不空的时候进行循环
{
front = (front + 1) % maxSize;
q = que[front]; //队头结点出队(front指向队头元素前一个位置)
visit(q);
if(q->lchild != NULL) //左子树不空,则其根结点入队
{
rear = (rear + 1) %maxSize;
que[rear] = q->lchild;
}
if(q->rchild != NULL) //右子树不空,则其根结点入队
{
rear = (rear + 1) %maxSize;
que[rear] = q->rchild;
}
}
}
}
typedef struct TBTNode
{
char data;
int ltag, rtag;
struct TBTNode *lchild;
struct TBTNode *rchild;
}TBTNode;
//通过中序遍历对二叉树线索化的递归算法
void InThread(TBTNode *p, TBTNode *&pre)
{
if(p != NULL)
{
InThread(p->lchild, pre); //递归,左子树线索化
if(p->lchild == NULL)
{ //建立当前结点的前驱线索
p->lchild = pre;
p->ltag = 1;
}
if(pre != NULL && pre->rchild == NULL)
{ //建立前驱结点的后继线索
pre->rchild = p;
pre-rag = 1;
}
pre = p;
InThread(p->rchild, pre); //递归,右子树线索化
}
}
//建立中序线索二叉树
void createInThread(TBTNode *root)
{
TBTNode *pre = NULL;
if(root != NULL)
{
InThread(root, pre);
pre->rchild = NULL;
pre->rtag = 1;
}
}
//求以p为根的中序线索二叉树中,中序序列下的第一个结点
TBTNode *First(TBTNode *p)
{
while(p->ltag == 0)
p = p->lchild; //最左下结点(不一定是叶子结点)
return p;
}
//求结点p在中序下的后继结点
TBTNode *Next(TBTNode *p)
{
if(p->rtag == 0)
return First(p->rchild);
else
return p->rchild; //rtag == 1,直接返回线索
}
//遍历
void InOrder(TBTNode *root)
{
for(TBTNode *p = First(root); p != NULL; p = Next(p))
visit(p);
}
//通过前序遍历对二叉树线索化的递归算法
void PreThread(TBTNode *p, TBTNode *&pre)
{
if(p != NULL)
{
if(p->lchild == NULL)
{ //建立当前结点的前驱线索
p->lchild = pre;
p->ltag = 1;
}
if(pre != NULL && pre->rchild == NULL)
{ //建立前驱结点的后继线索
pre->rchild = p;
pre-rag = 1;
}
pre = p;
if(p->ltag == 0) //左右指针不是线索才继续递归
PreThread(p->lchild, pre);
if(p->rtag == 0)
PreThread(p->rchild, pre);
}
}
//建立前序线索二叉树并遍历
void PreOrder(TBTNode *root)
{
if(root != NULL)
{
TBTNode *p = root;
while(p != NULL)
{
while(p->ltage == 0)//左指针不是线索,则边访问边左移
{
visit(p);
p = p->lchild;
}
}
visit(p); //此时p左指针比为线索,但还没有被访问
p = p->rchild; //此时p左孩子不存在,则右指针若非空,则不论是否为线索都指向其后继
}
}
//通过后序遍历对二叉树线索化的递归算法
void PostThread(TBTNode *p, TBTNode *&pre)
{
if(p != NULL)
{
PostThread(p->lchild, pre);
PostThread(p->rchild, pre);
if(p->lchild == NULL)
{ //建立当前结点的前驱线索
p->lchild = pre;
p->ltag = 1;
}
if(pre != NULL && pre->rchild == NULL)
{ //建立前驱结点的后继线索
pre->rchild = p;
pre-rag = 1;
}
pre = p;
}
}
void trave(BTNode *p)
{
if(p != NULL)
{
//(1) //若为先序遍历相关操作,则在该处添加相应代码
trave(p->lchild);
//(2) //若为中序遍历相关操作,则在该处添加相应代码
trave(p->rchild);
//(3) //若为后序遍历相关操作,则在该处添加相应代码
}
}
1. 表达式(a-(b+c)*(d/e)存储在一颗以二叉链表为存储结构的二叉树中(二叉树结点的data域为字符型),编写程序求表达式的值(表达式的操作数都是一位数的整数)
int op(int a, int b, char ch)
{
if(ch == '+') return a+b;
if(ch == '-') return a-b;
if(ch == '*') return a*b;
if(ch == '/')
{
if(b == 0)
return 0;
else
return a/b;
}
}
int comp(BTNode *p)
{
int A, B;
if(p != NULL)
{
if(p->lchild != NULL && p->rchild != NULL) //如果当前结点的左右子树都非空,则为表达式
{
A = comp(p->lchild);
B = comp(p->rchild);
return op(A, B, p->data);
}
else
return p->data-'0';
}
else
return 0;
}
2. 写一个算法求一棵二叉树的深度,二叉树以二叉链表为存储方式
int getDepth(BTNode *p)
{
int LD, RD;
if(p == NULL)
return 0; //如果是空树,返回0
else
{
LD = getDepth(p->lchild); //求左子树深度
RD = getDepth(p->rchild); //求右子树深度
return (LD > RD ? LD : RD)+1; //即求整棵树的深度
}
}
int getDepth(BTNode *p)
{
if(!p)
return 0;
int front = -1, rear = -1;
int last = 0, level = 0; //last指向当前层的最右结点
BTNode *Q[maxSize]; //设置队列Q,元素是二叉树结点指针且容量足够
Q[++rear] = p;
BTNode *q;
while(front < rear)
{
q = Q[++front]; //队列元素出队,即正在访问的结点
if(p->lchild)
Q[++rear] = p->lchild;
if(p->rchild)
Q[++rear] = p->rchild;
if(front == last) //某层元素遍历结束
{
++level; //层数加1
last = rear;
}
}
return level;
}
3. 在一棵以二叉链表为存储结构的二叉树中,查找data域值等于key的结点是否存在(找到在任何一个满足要求的结点即可),如果存在,则将q指向该结点,否则q赋值为NULL,假设data为int型
void search(BTNode *p, BTNode *&q, int key)
{
if(p != NULL) //如果树为空,则什么都不做,q保持NULL值
{
if(p->data == key)
q = p;
else
{
search(p->lchild, q, key);
if(q == NULL) //左子树中没找到才到右子树中查找
search(p->rchild, q, key);
}
}
}
4. 二叉树采用二叉链表存储结构存储,编写一个程序,输出先序遍历序列中第k个结点的值,假设k不大于总的结点数(结点data域为char型)
int n = 0; //定义全局变量n,将结点计数初值设为0
void trave(BTNode *p, int k)
{
if(p != NULL)
{
++n; //第一次来到一个结点就进行计数,表示这是第n个结点
if(k == n) //判断是不是第k个结点
{
cout<<p->data<<endl;
return;
}
trave(p->lchild, k);
trave(p->rchild, k);
}
}
5. 假设二叉树采用二叉链表存储结构,设计一个算法,求出该二叉树具有结点数最多的那一层上结点个数
typedef struct
{
BTNode *p; //结点指针
int lno; //结点所在层号
}St;
int maxNode(BTNode *b)
{
St que [maxSize];
int front, rear; //定义非循环队列
int Lno = 0, i, j, n, max = 0;
front = rear = 0; //将队列置空
BTNode *q;
if(b != NULL)
{
++rear;
que[rear].p = b; //树根入队
que[rear].lno = 1; //树根所在层次号设为1
while(front != rear)
{
++front;
q = que[front].p;
Lno = que[front].lno; //Lno用来存取当前结点的层次号
if(q->lchild != NULL)
{
++rear;
que[rear].p = q->lchild;
que[rear].lno = Lno+1; //根据当前结点的层次号推知其孩子的层次号
}
if(q->rchild != NULL)
{
++rear;
que[rear].p = q->rchild;
que[rear].lno = Lno+1;
}
}//循环结束的时候,Lno中保存的是这棵二叉树的最大层数
max = 0;
for(i = 1; i <= Lno; ++i)
{
n = 0;
for(j = 0; j < rear; ++j)
if(que[j].lno == i)
++n;
if(max < n)
max = n;
}
return max;
}
else
return 0;
}
6. 试给出二叉树的自下而上、从右到左的层次遍历方式
void invertLevel(BTNode *p)
{
int front, rear, top;
BTNode *que[maxSize], *stack[maxSize]; //定义一个循环队列和一个栈
front=rear=0, top=-1;
BTNode *q;
if(p != NULL)
{
rear = (rear+1) % maxSize;
que[rear] = p;
while(front != rear) //队不空的时候循环
{
front = (front+1) % maxSize;
q = que[front];
stack[++top] = q;
if(q->lchild != NULL) //若左子树不空,则左子树的根结点入栈
{
rear = (rear+1) % maxSize;
que[rear] = q->lchild;
}
if(q->rchild != NULL) //若右子树不空,则右子树的根结点入栈
{
rear = (rear+1) % maxSize;
que[rear] = q->rchild;
}
}
while(top != -1) //依次访问栈中元素
visit(stack[top--]->data);
}
}
7. 设一棵二叉树中各结点的值互不相同,其先序遍历序列和中序遍历序列分别存于两个一维数组A[1···n]和B[1···n]中,试编写算法建立该二叉树的二叉链表
BTNode *preInCreate(ElemType A[], ElemType B[], int LA, int RA, int LB, int RB)
{
root = (BTNode *)malloc(sizeof(BTNode)); //创建根结点
root->data = A[LA];
for(i = LB; B[i] != root->data; ++i); //根结点在中序序列的位置
Llen = i-LB; //左子树长度
Rlen = RB-i; //右子树长度
if(Llen)
root->lchild = preInCreate(A, B, LA+1, LA+Llen, LB, LB+Llen-1);
else
root->lchild = NULL;
if(Rlen)
root->rchild = preInCreate(A, B, RA-Rlen+1, LA, RB-Rlen+1, RB);
else
root->rchild = NULL;
return root;
}
8. 二叉树按二叉链表形式存储,判别给定二叉树是否是完全二叉树
bool IsComplete(BTNode *T)
{
int front=0, rear=0;
if(!T) //空树为满二叉树
return true;
BTNode *queue[maxSize]; //定义一个队列,且其空间足够长(或定义循环队列)
queue[++rear] = T;
BTNode *p;
while(front != rear) //遍历整棵树
{
p = queue[++front];
if(p)
{
queue[++rear] = p->lchild;
queue[++rear] = p->rchild; //若左右子树为空,则空结点入队
}
else //队列先进先出的特点,空结点出队
while(front != rear) //若后面有非空结点,则返回false
{
p = queue[++front];
if(p)
return false;
}
}
return true;
}
9. 二叉树采用二叉链表存储,计算一棵给定二叉树的所有双分支结点个数
int DsonNodes(BTNode *b)
{
if(b == NULL)
return 0;
else if(b->lchild != NULL && b->rchild != NULL)
return DsonNodes(b->lchild) + DsonNodes(b->rchild) + 1;
else
return DsonNodes(b->lchild) + DsonNodes(b->rchild);
}
10. 二叉树B采用链式存储,编写一个算法交换B中所有结点的左、右子树
void swap(BTNode *b)
{
if(b)
{
swap(b->lchild);
swap(b->rchild);
temp = b->lchild;
b->lchild = b->rchild;
b->rchild = temp;
}
}
11. 二叉树采用二叉链表存储,求先序遍历序列中第k(1 ≤ \le ≤k ≤ \le ≤二叉树中结点个数)个结点的值
int i = 1; //遍历序号的全局变量
ElemType PreNode(BTNode *b, int k)
{
if(b == NULL)
return '#'; //空结点,则返回特殊字符
if(i == k) //相等,则当前结点即为第k个结点
return b->data;
i++;
ch = PreNode(b->lchild, k); //左子树中递归寻找
if(ch != '#')
return ch;
ch = PreNode(b->rchild, k); //右子树中递归查找
return ch;
}
12. 二叉树采用二叉链表存储,编写算法,删去树中每个以元素值为x的结点为根的子树,并释放相应的空间
void DeleteXTree(BTNode *bt) //删除以bt为根的子树
{
if(bt)
{
DeleteXTree(bt->lchild); //删除bt的左右子树
DeleteXTree(bt->rchild);
free(bt);
}
}
void Search(BTNode *bt, ElemType x) //在二叉树上查找所有以x为元素值的结点,并删除以其为根的子树
{
int front = rear = 0;
BTNode *p;
BTNode *Q[maxSize]; //Q是存放二叉树结点指针的队列,容量足够大
if(bt)
{
if(bt->data == x) //若根结点值为x,则删除整棵树
{
DeleteXTree(bt);
exit(0);
}
Q[++rear] = bt;
while( front != rear)
{
p = Q[++front];
if(p->lchild) //若左子女非空
if(p->lchild->data == x) //左子树值等于x则删除左子树
{
DeleteXTree(p->lchild);
p->lchild = NULL; //左子女置空
}
else
Q[++rear] = p->lchild;
if(p->rchild) //若右子女非空
if(p->rchild->data == x) //右子树值等于x则删除右子树
{
DeleteXTree(p->rchild);
p->rchild = NULL; //右子女置空
}
else
Q[++rear] = p->rchild;
}
}
}
13. 二叉树中查找值为x的结点,打印值为x的结点的所有祖先,假设值为x的结点不多于一个
typedef struct
{
BTNode *t;
int tag; //tag=0表示左子女被访问,为1表示右子女被访问
}stack;
void Search(BTNode *bt, ElemType x)
{
stack s[maxSize]; //栈容量足够大
int top = 0;
while(bt != NULL || top > 0)
{
while(bt != NULL && bt->data != x) //结点入栈
{
s[++top].t = bt;
s[top].tag = 0;
bt = bt->lchild; //沿左分支向下
}
if(bt->data == x)
{
printg("所查结点的所有祖先结点的值为:\n");
for(int i =1; i <= top; i++);
printf("%d", t->data); //输出祖先值后结束
exit(1);
}
while(top != 0 && s[top].tag == 1)
--top; //退栈(空遍历)
if(top != 0)
{
s[top].tag = 1;
bt = s[top].t->rchild; //沿右分支向下遍历
}
}
}
14. 设一棵二叉树的结点结构为{LLINK, INFO, RLINK},ROOT为指向该二叉树根结点的指针,p和q分别为指向该二叉树中任意两个结点的指针,编写算法ANCESTOR{ROOT, p, q, r},找到p和q最近的公共祖先结点r
typedef struct
{
BTNode *t;
int tag; //tag=0表示左子女已被访问,tag=1表示右子女已被访问
}stack;
stack s[maxSize], s1[maxSize]; //容量足够大
BTNode *Ancestor(BTNode *root, BTNode *p, BTNode *q)
{
int top = 0;
BTNode *bt = root;
while(bt != NULL || top > 0)
{
while(bt != NULL && bt != p && bt != q) //结点入栈
{
while(bt != NULL)
{
s[++top].t = bt;
s[top].tag = 0;
bt = bt->lchild; //沿左分支向下
}
}
while(top != 0 && s[top].tag == 1) //假设p在q的左侧,遇到p时,栈中元素均为p的祖先
{
if(s[top].t == p)
{
for(int = 1; i <= top; i++) //将栈s的元素转入辅助栈s1保存
s1[i] = s[i];
top1 = top;
}
if(s[top].t == q) //找到q结点
{
for(i = top; i > 0; i--) //将栈中元素的树结点到s1中去匹配
for(int j = top1; j > 0; j--)
if(s1[j].t == s[i].t)
return s[i].t; //p和q的最近公共祖先已找到
--top; //退栈
}
}
if(top != 0)
{
s[top].tag = 1;
bt = s[top].t->rchild; //沿右分支向下遍历
}
}//while
return NULL; //p和q无公共祖先
}
15. 设有一棵满二叉树(所有结点值均不同),已知其先序序列为pre,设计一个算法求其后序序列post
void PreToPost(ElemType pre[], int l1, int h1, ElemType post[], int l2, int h2)
{
int half;
if(h1 >= l1)
{
post[h2] = pre[h1];
half = (h1-l1)/2;
PreToPost(pre ,l1+1, l1+half, post, l2, l2+half-1); //转换左子树
PreToPost(pre ,l1+half+1, h1, post, l2+half, h2-1); //转换右子树
}
}
16. 设计一个算法将二叉树的叶结点按从左到右的顺序连成一个单链表,表头指针为head。二叉树按二叉链表方式存储,链接时用叶结点的右指针域来存放单链表指针
LNode *head, *pre = NULL;
LNode *InOrder(BTNode *bt)
{
if(bt)
{
InOrder(bt->lchild); //中序遍历左子树
if(bt->lchild == NULL && bt->rchild == NULL) //叶结点
if(pre == NULL) //处理第一个叶结点
{
head = bt;
pre = bt;
}
else
{
pre->rchild = bt;
pre = bt;
}
InOrder(bt->rchild); //中序遍历右子树
pre->rchild = NULL; //设置链表尾
}
return head;
}
17. 试设计判断两棵二叉树是否相似的算法。所谓二叉树T1和T2相似,指的是T1和T2都是空的二叉树或只有一个根结点;或T1的左子树和T2的左子树是相似的,且T1的右子树和T2的右子树是相似的
int similar(BTNode *T1, BTNode *T2)
{
int leftS, rightS;
if(T1 == NULL && T2 == NULL)
return 1;
else if(T1 == NULL || T2 == NULL)
return 0;
else
{
leftS = similar(T1->lchild, T2->lchild);
rightS = similar(T1->rchild, T2->rchild);
return leftS && rightS;
}
}
18. 写出在中序线索二叉树里查找指定结点在后序的前驱结点的算法
TBTNode * InPostPre(TBTNode *t, TBTNode *p)
{
TBTNode *q;
if(p->rtag == 0) //若p有右子女,则右子女时其后序前驱
q = p->rchild;
else if(p->ltag == 0) //若p只有左子女,则左子女时其后序前驱
q = p->lchild;
else if(p->lchild == NULL)
q = NULL; //p是中序序列第一结点,无后序前驱
else //顺左线索向上找p的祖先,若存在,再找祖先的左子女
{
while(p->ltag == 1 && p->lchild != NULL)
p = p->lchild;
if(p->ltag == 0)
q = p->lchild; //p结点的祖先的左子女是其后序前驱
else
q = NULL; //仅有单支树(p是叶子),已到根结点,p无后序前驱
}
return q;
}
19. 二叉树的带权路径长度是二叉树中所有叶结点的带权路径长度之和。给定一棵二叉树T,采用二叉链表存储,结点结构为[left, weight, right],其中叶结点的weight域保存该结点的非负权值。设root为指向T的根结点的指针,设计算法求T的WPL
typedef struct BTNode
{
int weight;
struct BTNode *lchild, *rchild;
}BTNode;
//基于先序遍历的算法
int WPL(BTNode *root)
{
return wpl_PreOrder(root, 0);
}
int wpl_PreOrder(BTNode *root, int deep)
{
static int wpl = 0; //静态变量只初始化一次,以后每次调用仅改变其值
if(root->lchild == NULL && root->rchild == NULL)//若为叶结点,则累积wpl
wpl += deep*root->weight;
if(root->lchild != NULL) //若左子树不空,则递归遍历左子树
wpl_PreOrder(root->lchild, deep+1);
if(root->rchild != NULL) //若右子树不空,则递归遍历右子树
wpl_PreOrder(root->rchild, deep+1);
return wpl;
}
//基于层次遍历的算法
#define maxSize 100 //设置队列的最大容量
int wpl_LevelOrder(BTNode *root)
{
BTNode *q[maxSize]; //定义队列
int end1, end2; //end1队头指针,end2队尾指针
end1 = end2 = 0; //头指针指向队头元素,尾指针指向队尾的后一个元素
int wpl = 0, deep = 0;
BTNode *lastNode; //lastNode用来记录当前层的最后一个结点
BTNode *newlastNode; //newlastNode用来记录下一层的最后一个结点
lastNode = root; //lastNode初始化为根结点
newlastNode = NULL; //newlastNode初始化为空
q[end2++] = root; //根结点入队
while(end1 != end2) //层次遍历,若队列不空则循环
{
BTNode *t = q[end1++]; //拿出队列中的一个头元素
if(t->lchild == NULL && r->rchild == NULL) //若为叶结点,统计wpl
wpl += deep*t->weight;
if(t->lchild != NULL) //若非叶结点,把左结点入队
{
q[end2++] = t->lchild;
newlastNode = t->lchild; //设下一层的最后一个结点为该结点的左结点
}
if(t->rchild != NULL) //处理叶结点
{
q[end2++] = t->rchild;
newlastNode = t->rchild;
}
if(t == lastNode) //若该结点为本层最后一个结点,则更新lastNode
{
lastNode = newlastNode;
deep += 1; //层数加1
}
}
return wpl;
}
20. 设计一个算法,将给定的表达式树(二叉树)转换为等价的中缀表达式(通过括号反应操作符的计算次序)并输出
typedef struct node
{
char data[10]; //存储操作数或操作符
struct node *left, *right;
}BTree;
void BTreeToE(BTNode *root)
{
BTreeToE(root, 1); //根的高度为1
}
void BTreeToExp(BTNode *root, int deep)
{
if(root == NULL)
return; //空结点返回
else if(root->left == NULL && root->right == NULL)
printf("%s", root->data); //输出操作数,不加括号
else
{
if(deep > 1)
printf("("); //若有子表达式则加1层括号
BTreeToExp(root->left, deep+1);
printf("%s", root->data); //输出操作符
BTreeToExp(root->right, deep+1);
if(deep > 1)
printf(")"); //若有右表达式则加1层括号
}
}
1. 求以孩子兄弟表示法存储的森林的叶子结点数
typedef struct BTNode
{
ElemType data;
struct BTNode *fch, *nsib; //孩子域与兄弟域
}BTNode;
int Leaves(BTNode *bt)
{
if(bt == NULL) //树空返回0
return 0;
if(t->fch == NULL) //若结点无孩子,则该结点必是叶子
return 1+Leaves(bt->nsib); //返回叶子结点和其兄弟子树中的叶子结点数
else
return Leaves(bt->fch) + Leaves(bt->nsib); //返回孩子子树和兄弟子树中叶子数之和
}
2. 以孩子兄弟链表为存储结构,涉及递归算法求树的深度
int Height(BTNode *bt)
{
int hc, hs;
if(bt == NULL)
return 0;
else
{
hc = Height(bt->fch);
hs = Height(bt->nsib);
if(hc+1 > hs)
reutrn hc+1;
else
return hs;
}
}
3. 已知一棵树的层次序列及每个结点的度,编写算法构造此树的孩子兄弟链表
#define maxNode 15
void createGSTree_Degree(BTNode *&T, DateType e[], int degree[], int n)
{
BTNode *pointer = new BTNode[maxNodes];
int i, j, d, k=0;
for(i = 0; i < n; ++i)
{
pointer[i]->data = e[i];
pointer[i]->lchild = pointer[i]->rchild = NULL;
}
for(i = 0; i < n; ++i)
{
d = degree[i]; //结点i的度数
if(d)
{
++k; //k为子女结点序号
pointer[i]->lchild = pointer[k]; //建立i与子女k间的链接
for(j = 2; j <= d; ++j)
pointer[(++k)-1]->rchild = pointer[k];
}
}
T = pointer[0];
delete[] pointer; //释放数组
}
BSTNode *BST_Search(BTNode *T, ElemType key)
{
while(T != NULL && key != T->data)
{
if(key < T->data)
T = T->lchild;
else
T = T->rchild;
}
return T;
}
int BST_Insert(BTNode *&T, KeyType k)
{
if(T == NULL) //原树为空,新插入的记录为根结点
{
T = (BTNode *)malloc(sizeof(BTNode));
T->key = k;
T->lchild = T->rchild = NULL;
return 1; //返回1,插入成功
}
else if(k == T->key) //树中存在相同关键字的结点,插入失败
return 0;
else if(k < T->key) //插入到T的左子树
return BST_Insert(T->lchild, k);
else //插入到T的右子树
return BST_Insert(T->rchild, k);
}
void Create_BST(BTNode *&T, KeyType str[], int n)
{
T = NULL; //初始时T为空树
int i = 0;
while(i < n) //依次将每个关键字插入到二叉排序树中
{
BST_Insert(T, str[i]);
i++;
}
}
主要取决于树的高度
插入:首先检查其插入路径上的结点是否因为此次操作而导致了不平衡,若导致了不平衡,则先找到插入路径上离插入结点最近的平衡因子的绝对值大于1的结点A,再对以A为根的子树,在保持二叉排序树特性的前提下,调整各结点的位置关系,使之重新达到平衡
LL旋转:结点A的左孩子的左子树插入了新结点。
RR旋转:结点A的右孩子的右子树插入了新结点
LR旋转:结点A的左孩子的右子树插入了新结点
RL旋转:结点A的右孩子的左子树插入了新结点
LR和RL旋转时,新结点究竟是插入C的左子树还是右子树不影响旋转过程
#define VERTICES 6
void initialise(int parent[], int rank[]){ //父结点数组、深度数组初始化
int i;
for(i = 0; i < VERETICES; i++){
parent[i] = -1;
rank[i] = 0;
}
}
int find_root(int x, int parent[]){ //找指定结点的根结点
int x_root = x;
while(parent[x_root] != -1)
x_root = parent[x_root];
return x_root;
}
/**
* 1---union successfully 俩结点不在同一集合时,合并
* 0---failed 否则不合并
*/
int union_vertices(int x, int y, int parent[], int rank[]){
int x_root = find_root(x, parent);
int y_root = find_root(y, parent);
if(x_root == y_root)
return 0;
else{
if(rank[x_root] > rank[y_root]){ //x根结点深度 > y根结点深度,y认x做老大
parent[y_root] = x_root;
}else if(rank[x_root] < rank[y_root]){ //x根结点深度 < y根结点深度,x认y做老大
parent[x_root] = y_root;
}else{ //x根结点深度 < y根结点深度,让x做老大,高度加1
rank[x_root]++;
parent[y_root] = x_root;
}
return 1;
}
}
int main(){
int parent[VERTICES] = {0};
int edges[6][2] = {
{0,1}, {1,2}, {1,3},
{2,4}, {3,4}, {2,5}
};
initialise(parent);
int i;
for(i = 0; i < 6; i++){
int x = edges[i][0];
int y = edges[i][1];
if(union_vertices(x, y, parent) == 0){
printf("Cycle detected!"\n);
exit(0);
}
}
printf("No cycle found."\n);
}
新插入结点默认为红色
③插入9
④插入2
⑤插入0
⑥插入11
⑦插入7
⑧插入19
⑨插入4
⑩插入15
⑪插入18
⑫插入5
⑬插入14
⑭插入13
⑮插入10
⑯插入16
⑰插入6
⑱插入3
第一步:从树中删除结点X(以寻找后继结点的方式删除)
第二步:旋转调色
①删除12
②删除1
③删除9
④删除2
⑤删除0
⑥删除11
⑦删除7
⑧删除19
⑨删除4
⑩删除15
⑪删除18
⑫删除5
⑬删除14