icoding复习5 树 感觉难度巨大....
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;
}
總結
以上是生活随笔為你收集整理的icoding复习5 树 感觉难度巨大....的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: icoding复习4 数组 十字链表
- 下一篇: icoding复习7, 8