几道二叉树的代码
FIRST
在二叉树中查找 data 域的值等于 key 的结点是否存在,如果存在,则将 q 指向该结点,否则 q 赋值为 NULL, 假设 data 为 int 型
解法一:
/*假设二叉树已经存在且 p 指向其根节点*/
void search(BTNode *p, BTNode *&q, int key)
/*注意要将参数 q 定义为引用型指针,因为 q 要改变*/
{
if(p)
{
if(p -> data == key)
q = p;
else
{
search(p->lchild, q, key);
search(p->rchild, q, key);
}
}
}
解法二:
void search(BTNode *p, BTNode *&q, int key)
{
if(p)
{
if(p->data == key)
q = p;
else
{
search(p->lchild, q, key);
if(q == NULL) // 左子树搜索不到才到右子树去查找
search(p->rchild, q, key);
}
}
}
SECOND
输出先序序列遍历中第 k 个结点的值
int n = 0;
void trave(BTNode *p, int k)
{
if(p)
{
++n;
if(k == n)
{
cout << p -> data << endl;
return;
}
trave(p->lchild, k);
trave(p->rchild, k);
}
}
THIRD
二叉树的层次遍历
void level(BTNode *p)
{
int front, rear;
BTNode *que[maxSize]; // 定义一个循环队列,用来记录要访问的层次上的结点
BTNode *q;
front = rear = 0;
if(p)
{
rear = (rear+1) % maxSize;
que[rear] = p; // 根节点入队
while(front != rear) // 当队列不为空时进行循环
{
front = (front+1) % maxSize;
q = que[front]; // 队头结点出队
visit[q]; // 访问队头结点
if(q -> lchild)
{
rear = (rear+1) % maxSize;
que[rear] = q -> lchild;
}
if(q->rchild)
{
rear = (rear+1) % maxSize;
que[rear] = q -> rchild;
}
}
}
}
FORTH
一个完全二叉树按顺序存储结构存储在数组 tree[] 中,假设二叉树结点值类型为 char 型,结点个数为 n,设计一个算法,求出离下标分别为 i 和 j 的两个结点最近的公共祖先结点的值。
char ancestor(char tree[], int i, int j)
{
int p = i, q = j;
while(p != q)
{
if(p > q)
p = p / 2; // p 往上走
else
q = q / 2; // q 往上走
}
return tree[p];
}
FIFTH
已知二叉树的结点按先序遍历下的序列存储在一维数组 pre[left_1,……,right_1] 中,按中序遍历下的序列存储在一维数组 in[left_2,……,right_2] 中。写出由先序和中序序列构造二叉树的算法。
BTNode *CreateBT[cha pre[], char in[], int left_1, int right_1, int left_2, int right_2]
{
BTNode *s;
int i;
if(left_1 > right_1)
return NULL;
s = (BTNode *s)malloc(sizeof(BTNode));
s -> lchild = s -> rchild = NULL;
//查找等于当前子树根的结点在 in[] 中的位置
for(i = left_2; i <= right_2; i++)
if(in[i] == pre[left_1])
break;
s -> data = in[i];
/*通过在 in[] 中找到分界点 i, 确定在 pre[] 和 in[] 中当前子树的左子树范围,再仿照之前的方法建立左子树,将左子树根连接在 s 的左指针域上*/
s -> lchild = CreateBT(pre, in, left_1 + 1, left_1 + (i - left_2), left_2, i-1)
s -> rchild = CreateBT(pre, in, left_1 + 1, left_1 + (i - l2), left_2, i-1)
}
SIXTH
计算一棵给定二叉树的所有结点数
解法一:
int n;
void count(BTNode *p)
{
if(p)
{
n++;
count(p -> lchild);
count(p -> rchild);
}
}
解法二:
int count(BTNode *p)
{
int n1, n2;
if(!p)
return NULL;
else
{
n1 = count(p -> lchild);
n2 = count(p -> rchild);
return n1+n2+1; // 每次都要加上当前根节点
}
}
SEVENTH
计算一棵二叉树的所有叶子结点数
解法一:
int n;
void count(BTNode *p)
{
if(p)
{
if(!p->lchild && ! p->rchild)
n++;
count(p -> lchild);
count(p -> rchild);
}
}
解法二:
int count(BTNode *p)
{
int n1, n2;
if(!p)
return 0;
else if(!p->lchild && !p->rchild)
return 1;
else
{
n1 = count(p -> lchild);
n2 = count(p -> rchild);
return n1+n2;
}
}
EIGHTH
利用结点的 rchild 指针,将叶子结点从左往右串成一个单链表
void link(BTNode *p, BTNode *&head, BTNode *&tail)
{
if(p)
{
if(!p->lchild && !p->rchild)
{
if(!head) /*如果 head == NULL, 说明这是第一个叶子结点*/
{
head = p;
tail = p;
}
else
{
tail -> rchild = p;
tail = p;
}
link(p->lchild, head, tail);
link(p->rchild, head, tail);
}
}
}
NINTH
二叉树采用二叉链式存储结构,增加一个指向双亲结点的 parent 指针,设计一个算法,给这个结点赋值,并输出所有结点到根结点的路径
typedef struct BTNode
{
char data;
BTNode *lchild;
BTNode *rchild;
BTNode *parent;
}BTNode;
BTNode *q = NULL;
void triBtree(BTNode *p, BTNode *q)
{ /*参数 q 始终指向当前访问结点 p 的双亲结点。当 P 为根结点时, q 应为 NULL*/
if(p)
{
p -> praent = q;
q = p;
triBtree(p -> lchild);
triBtree(p -> rchild);
}
}
void printPath(BTNode *p)
{
while(p)
{
cout << p -> data << " ";
p = p -> parent;
}
}
void allPath(BTNode *p)
{
if(p)
{
printPath(p);
allPath(p->lchild);
allPath(p->rchild);
}
}
TENTH
求二叉树中值为 x 的结点的层号
int L = 1;
void leno(BTNode *p)
{
if(p)
{
if(p->data == x)
cout << L << endl;
}
++L;
leno(p->lchild, x);
leno(p->rchild, x);
/*这两句执行完后,p 指针要由下一层返回到上一层了,所以要 --L*/
--L;
}
ELEVENTH
设计算法,输出根结点到每个叶子结点的路径
int i;
int top = -1;
char pathStack[maxSize];
void allPath(BTNode *p)
{
if(p)
{
pathStack[++top] = p -> data;
if(!p->lchild && !p->rchild)
{
for(i = 0; i <= top; i++)
cout << pathStack[i];
}
allPath(p->lchild);
allPath(p->rchild);
--top; /*所访问结点出栈*/
}
}
TWELFTH
二叉树先序遍历的非递归算法
void preOrder(BTNode *root)
{
BTNode *Stack[maxSize];
int top = -1;
BTNode *p;
if(bt)
{
Stack[++top] = bt; /*入栈顺序:根 -> 右 -> 左*/
while(top != -1)
{
p = Stack[top--];
cout << p->data << " ";
if(p->rchild)
Stack[++top] = p -> rchild;
if(p->lchild)
Stack[++top] = p -> lchild;
}
}
}
二叉树中序遍历的非递归算法
void inOrder(BTNode *root)
{
BTNode *Stack[maxSize];
int top = -1;
BTNode *p;
if(root)
{
p = root;
/*在出栈过程中会出现栈空状态,但这时遍历还没有结束,因根结点的右子树还没有遍历,此时 p 非空,根据这一点来维持循环队的进行*/
while(top != -1 || p)
{
while(p) /*左孩子先全部入栈*/
{
Stack[++top] = p;
p = p -> lchild;
}
if(top != -1)
{
p = Stack[top--];
cout << p -> data << " ";
p = p -> rchild;
}
}
}
}
二叉树后序遍历的非递归算法
void Postorder(BTNode* t)
{
BTnode* Seqstack[MAXSIZE];
int top = -1;
int falg = 1;
BTnode* p;
if(t != NULL)
{
do
{
while(t != NULL) // 循环,将所有最左结点压栈
{
top ++;
Seqstack[top] = t;
t = t->lchild;
}
flag = 1;
// 辅助变量flag为1表示当前结点的左孩子为空或者已被访问
p = NULL;
// 指针变量p指向当前结点的前驱结点
while(top > -1&& falg == 1)
{
t = Seqstack[top];
// 注意:这里只是获取栈顶元素,而并没有出栈
if(t->rchild == p)
// 如果当前结点右孩子为空,或者已经被访问过,则访问当前结点
{
top --; // 当前结点出栈
printf("%d ", p->data);
p = t; // 指针变量指向当前结点
}
else // 如果当前结点右孩子不为空,则先去处理右孩子
{
t = t->rchild; // 处理右孩子
flag = 0;
// *t的左孩子未被访问,flag置为0
}
}
}while(top > -1)
}
}
将二叉树 bt 中每一个结点的左右子树互换
void Exchange(BTNode *bt)
{
BTNode *p, *q;
if(bt)
{
EnQueue(Q,bt);
while(!Empty(Q))
{
p = DeQueue(Q);
if(p->lchild)
EnQueue(p->lchild);
if(p->rchild)
EnQueue(p->rchild);
q = p -> rchild;
p -> rchild = p -> lchild;
p -> lchild = q;
}
}
}
求二叉树的高度
int Height(BTNode *p)
{
if(p)
{
if(!p->lchild)
lh = 0;
else
lh = Height(p->lchild);
if(!p->rchild)
rh = 0;
else
rh = Height(p->rchild);
if(lh > rh)
hi = lh + 1;
else
hi = rh + 1;
}
else
hi = 0;
return hi;
}
求出以 T 为根的二叉树的结点个数
int size(BTNode *T)
{
if(!T)
return 0;
else
return 1 + size(T->lchild) + size(T->rchild);
}
计算根为 r 的树中叶子结点的个数
int numberofleaf(BTNode *r)
{
int num;
if(!r)
num = 0;
else if(!l->lchild)
num = 1 + numberofleaf(r->rchild);
else
num = numberofleaf(r->lchild) + numberofleaf(r->rchild);
return num;
}