icoding 复习5
1. 先序遍历
已知二叉树按照二叉链表方式存储,利用栈的基本操作写出先序遍历非递归形式的算法:
void pre_order(BiTree root);
二叉树的相关定义如下:
typedef int DataType;
typedef struct Node{
DataType data;
struct Node* left;
struct Node* right;
}BiTNode, *BiTree;
遍历所使用栈的相关操作如下:
#define Stack_Size 50
typedef BiTNode* ElemType;
typedef struct{
ElemType elem[Stack_Size];
//BiTNode* elem[Stack_Size]
int top;
}Stack;
void init_stack(Stack *S); // 初始化栈
bool push(Stack* S, ElemType x); //x 入栈
bool pop(Stack* S, ElemType *px); //出栈,元素保存到px所指的单元,函数返回true,栈为空时返回 false
bool top(Stack* S, ElemType *px); //获取栈顶元素,将其保存到px所指的单元,函数返回true,栈满时返回 false
bool is_empty(Stack* S); // 栈为空时返回 true,否则返回 false
在遍历过程中,pre_order函数需要调用 visit_node 函数来实现对结点的访问,该函数声明如下:
void visit_node(BiTNode *node);
#include
#include
#include "bitree.h" //请不要删除,否则检查不通过
大概率考原题和改编!!!!!!
void pre_order(BiTree root){
if(!root) return;
Stack *S;
BiTNode *p;
init_stack(S);
push(S, root->data);
while(!is_empty(S)){
pop(S, &p);
visit_node(p);
if(p->left)
push(S, p->left);
if(p->right){
push(S, p->right);
}
}
}
//解法2, 声明为Stack S;
void pre_order(BiTree root)
{
Stack S;
BiTNode *p, *q;
// S.top = -1; 初始化应该会赋值
p = root;
init_stack(&S);
if (p == NULL)
return;
do {
if (p) {
visit_node(p);//先序遍历的核心,先访问根节点
push(&S, p);
p = p->left;
} else {
pop(&S, &p);
p = p->right;
}
} while (p || !(is_empty(&S)));
}
//中序遍历
void InOrder(BiTNode *root){
Stack *S; BiTNode *p;
init_stack(S);
if(!root ) return;
while(p || !is_empty(S)){
while(p){
push(S, p);
p = p->left;
}
if(!is_empty(S)){
pop(S, &p);
visit_node(p);
p = p->right;
}
}
}
//后序遍历非递归 难
void PostOrder(BiTNode *root){
Stack *S; BiTNode *p, *r; bool flag;
init_stack(S);
p = root;
do{
while(p){
push(S, p);
p = p->left;
}
r = NULL;
flag = true;
while(!is_empty(S) && flag){
top(S, &p);
if(p->right == r){
visit_node(p);
pop(S, &p);
r = p;
}
else{
p = p->right;
flag = false;
}
}
}while(!is_empty(S));
}
2. 路径
假设二叉树采用二叉链表方式存储, root指向根结点,node 指向二叉树中的一个结点,
编写函数 path,计算root到 node 之间的路径,(该路径包括root结点和 node 结点)。path 函数声明如下:
bool path(BiTNode* root, BiTNode* node, Stack* s);
其中,root指向二叉树的根结点,node指向二叉树中的另一结点,s 为已经初始化好的栈,
该栈用来保存函数所计算的路径,如正确找出路径,则函数返回 true,此时root在栈底,node在栈顶;
#include "bitree.h" //请不要删除,否则检查不通过
#include
#include
bool path(BiTNode* root, BiTNode* node, Stack* s){
BiTNode *p, *q;
if(!root || !node) return false;
p = root;
if(p == node){
push(s, p);
return true;
}
while(p || !is_empty(s)){
while(p){//先压入再判断
push(s, p);
if(p == node)
return true;
p = p->left;
}
top(s, &p);
if(p->right == q || p->right == NULL){
q = p;
top(s, &p);
p = NULL;
}
else
p = p->right;
}
return true;
}
3. 共同祖先
假设二叉树采用二叉链表方式存储, root指向根结点,p所指结点和q所指结点为二叉树中的两个结点,
编写一个计算它们的最近的共同祖先,函数定义如下:
BiTNode * nearest_ancestor(BiTree root, BiTNode *p, BiTNode *q);
其中 root 指向二叉树的根结点,p 和 q 分别指向二叉树中的两个结点。
提示:在完成本题时,可利用 path 函数获取p和q两个结点到根结点之间的路径,
之后再计算两条公共路径得出最近的共同祖先。path函数及栈相关定义如下:
#include
#include
#include "bitree.h" //请不要删除,否则检查不通过
BiTNode * nearest_ancestor(BiTree root, BiTNode *p, BiTNode *q){
if(!root || !p || !q) return NULL;
Stack *s1, *s2;
init_stack(s1); init_stack(s2);
path(root, p, s1);
path(root, q, s2);
for(int i = 0; s1->elem[i] == s2->elem[i]; i++)
;
return s1->elem[i-1];
}
4. 树转二叉树
使用队列,编写transfrom函数,将普通树转换成对应的二叉树。二叉树的相关定义如下:
typedef int DataType;
typedef struct Node{
DataType data;
struct Node* left;
struct Node* right;
}BiTNode, *BiTree;
普通树节点 的定义如下:
#define MAX_CHILDREN_NUM 5
struct _CSNode
{
DataType data;
struct _CSNode *children[MAX_CHILDREN_NUM];
};
typedef struct _CSNode CSNode;
其中,子树的根节点的指针存放在children数组的前k个元素中,即如果children[i]的值为NULL,
而children[i-1]不为NULL,则表明该结点只有i棵子树,子树根结点分别保存在children[0]至children[i-1]中。
队列相关定义及操作如下:
struct __Queue
{
int i, j; //指向数组内元素的游标
void **array;//这个就是提示!!!!!!!!!!!!!!!!!!!!!!!!!!!
};
typedef struct __Queue Queue;
Queue* create_queue(); //创建队列
bool is_empty_queue(Queue *tree); //队为空返回true,不为空时返回false
void* del_queue(Queue *tree); //结点指针出队
void add_queue(Queue *tree, void *node); //结点指针入队
void free_queue(Queue *tree); //释放队列
transform函数定义如下:
BiTNode* transform(CSNode *root);
其中 root 为普通树的根结点,函数返回该树对应二叉树的根结点。
#include
#include
#include "bitree.h" //请不要删除,否则检查不通过
BiTNode* transform(CSNode *root){
if(!root) return NULL;
Queue *que, *bque;
BiTNode *p;
//二叉树根结点创立
//小心点, 记得分配空间
//为什么想到建立二叉树结点?
//普通树结点和二叉树结点无法强制类型转换
p = (BiTNode *)malloc(sizeof(struct Node));
p->data = root->data;
p->left = p->right = NULL;
que = create_queue();
bque = create_queue();
//建立双队目的在于建立有序二叉结点序列
add_queue(que, root);
add_queue(bque, p);
//注意这个while怎么处理好孩子与孙子关系的, 没用递归!!!
while(!is_empty_queue(que)){
BiTree bq;//创建二叉树队列头结点(根结点)
bq = del_queue(bque);
CSNode *q;
q = del_queue(que);
//第一次执行该操作就相当于建立了二叉树的根
int i = 0;
BiTNode *former = NULL;
for(i = 0; i < MAX_CHILDREN_NUM; i++){
if(q->children[i]){//判存在
BiTNode *bnode = (BiTNode *)malloc(sizeof(struct Node));
bnode->data = q->children[i]->data;
bnode->left = bnode->right = NULL;
//放置结点位置
if(i == 0){
bq->left = bnode;
}
else{//兄弟变为孩子了可怜
former->right = bnode;
}
former= bnode;
add_queue(bque, bnode);
add_queue(que, q->children[i]);
}
}
}
free(que->array);
free(que);
free(bque->array);
free(bque);
return p;
}