1. 程式人生 > >例題6-7 樹的層次遍歷

例題6-7 樹的層次遍歷

integer 建二叉樹 let mes 寬度 als 題意 who min

Trees on the level

Trees are fundamental in many branches of computer science (Pun definitely intended). Current stateof-the
art parallel computers such as Thinking Machines’ CM-5 are based on fat trees. Quad- and
octal-trees are fundamental to many algorithms in computer graphics.
This problem involves building and traversing binary trees.
Given a sequence of binary trees, you are to write a program
that prints a level-order traversal of each tree. In this
problem each node of a binary tree contains a positive integer
and all binary trees have have fewer than 256 nodes.
In a level-order traversal of a tree, the data in all nodes at
a given level are printed in left-to-right order and all nodes at
level k are printed before all nodes at level k + 1.
For example, a level order traversal of the tree on the right
is: 5, 4, 8, 11, 13, 4, 7, 2, 1.
In this problem a binary tree is specified by a sequence
of pairs ‘(n,s)’ where n is the value at the node whose path
from the root is given by the string s. A path is given be
a sequence of ‘L’s and ‘R’s where ‘L’ indicates a left branch and ‘R’ indicates a right branch. In the
tree diagrammed above, the node containing 13 is specified by (13,RL), and the node containing 2 is
specified by (2,LLR). The root node is specified by (5,) where the empty string indicates the path from
the root to itself. A binary tree is considered to be completely specified if every node on all root-to-node
paths in the tree is given a value exactly once.
Input


The input is a sequence of binary trees specified as described above. Each tree in a sequence consists
of several pairs ‘(n,s)’ as described above separated by whitespace. The last entry in each tree is ‘()’.
No whitespace appears between left and right parentheses.
All nodes contain a positive integer. Every tree in the input will consist of at least one node and
no more than 256 nodes. Input is terminated by end-of-file.
Output

For each completely specified binary tree in the input file, the level order traversal of that tree should
be printed. If a tree is not completely specified, i.e., some node in the tree is NOT given a value or a
node is given a value more than once, then the string ‘not complete’ should be printed.
Sample Input

(11,LL) (7,LLL) (8,R)
(5,) (4,L) (13,RL) (2,LLR) (1,RRR) (4,RR) ()
(3,L) (4,R) ()
Sample Output
5 4 8 11 13 4 7 2 1
not complete

題目鏈接:https://vjudge.net/problem/UVA-122

題意:

(11,LL)表示節點值為11,在第二層的左,第三層的左;
(5,)表示根節點;
總之,每一個L或者R代表從root到達該節點在每一層的轉向,問,給一串這樣的字符串,輸出二叉樹層序遍歷的結果,
如果輸入重復或者節點的val為0則表示輸出錯誤“not complete”.

題解:

根據輸入構造二叉樹,然後用queue層序遍歷輸出即可。
(1)根據輸入創建二叉樹,技巧:sscanf(&s[1], "%d", &v),從數組中讀取數字,strchr(s, ‘,‘)+1獲取數字後的字符串最後一個‘)‘在處理時忽略;
(2)指針實現時,記得deletenode,root要先newnode;
(3)數組實現時,各節點按順序存放,通過lf[maxn]和rt[maxn]數組確定左右節點;
(4)註意,已經有值的節點重復賦值要另flag = false,以及層序遍歷時出現未賦值節點也要flag = false.

分析:

1。在輸入方面,直接開了一個bool read_input()函數,這樣在輸入EOF時,就返回false,所以可以在main函數裏直接這樣寫:while(read_input()){...}。

2。在這個read_input 函數裏面,用到了sscanf (&s[1]),這樣就把字符串從位置1開始的字符串後面讀取整數!,後面又用到了strchr(s,‘,‘)把逗號後面的字符串提取出來。

3。在結構體node裏面,用了一個構造函數,不僅把have_value這個關鍵變量初始化為false,並且把一個node 裏面的left,right也初始化到NULL,在前面學字典樹時,就沒這樣做,而是new node後再用循環初始化NULL,這裏直接用構造函數初始化,就感覺比較巧妙了。

3。遍歷二叉樹時用了bfs+隊列,先判斷left,在判斷right,這樣就保證了輸出順序的正確性,

4。最後釋放內存用到了遞歸釋放內存,類似於字典樹。

指針實現代碼

//#include <bits/stdc++.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
#include<string.h>
#include<string>
#include<stack>
#include<queue>
#include<iostream>
#define INF 0xffffffff
using namespace std;
typedef long long ll;

const int maxn = 300;

char s[maxn];
bool failed;
vector<int> a; 

struct Node{
    bool have_value;
    int v;
    Node *left, *right;
    Node():have_value(false), left(NULL), right(NULL){}
};
Node* root;

Node* newnode(){
    return new Node();
}

void addnode(int v, char* s){
    int n = strlen(s);
    Node *u = root;
    for(int i=0; i<n; i++){
        if(s[i] == L){
            if(u->left == NULL) u->left = newnode();
            u = u->left;
        }
        else if(s[i] == R){
            if(u->right == NULL) u->right = newnode();
            u = u->right;
        }
    }
    if(u->have_value) failed = true;
    u->v = v;
    u->have_value = true;
}

void remove_tree(Node* u){
    if(u == NULL) return;
    remove_tree(u->left);
    remove_tree(u->right);
    delete u;
}

bool read_input(){
    failed = false;
    remove_tree(root);
    root = newnode();
    for(;;){
        if(scanf("%s", s) != 1) return false;
        if(!strcmp(s, "()")) break;
        int v;
        sscanf(&s[1], "%d", &v);
        addnode(v, strchr(s, ,)+1);
    }
    return true;
}

bool bfs(vector<int>& ans){
    queue<Node*> q;
    ans.clear();
    q.push(root);
    while(!q.empty()){
        Node *u = q.front();
        q.pop();
        if(!u->have_value) return false;
        ans.push_back(u->v);
        if(u->left != NULL) q.push(u->left);
        if(u->right != NULL) q.push(u->right);
    } 
    return true;
}

int main(){
    while(read_input()){
        if(bfs(a) && !failed){
            for(int i=0; i<a.size(); i++){
                if(i >0) printf(" ");
                printf("%d", a[i]);
            }
            printf("\n");
        }
        else{
            printf("not complete\n");
        }
    }
    return 0;
}

數組實現代碼

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
#include<string.h>
#include<string>
#include<stack>
#include<queue>
#include<iostream>
using namespace std;
typedef long long ll;
const int maxn=300;
const int root=1;
int lf[maxn];
int rt[maxn];
bool hv[maxn];
int val[maxn];
vector<int> ans;
bool flag;
int cnt;
void newtree()
{
    cnt=root;
    lf[root]=rt[root]=0;
    hv[root]=false;
}
int newnode()
{
    int u=++cnt;
    lf[u]=rt[u]=0;
    hv[u]=false;
    return u;

}
void addnode(int v,char *s)
{
    int n=strlen(s);
    int u=root;
    for(int i=0; i<n; i++)
    {
        if(s[i]==L)
        {
            if(lf[u]==0) lf[u]=newnode();//節點不存在,建立新節點
            u=lf[u];//往左走
        }
        else if(s[i]==R)
        {
            if(rt[u]==0) rt[u]=newnode();
            u=rt[u];
        }//忽略其他情況 即最後那個多余的右括號

    }
    if(hv[u]) flag=false;//have_value 本身已經有值
    val[u]=v;
    hv[u]=true;
}
bool input()
{
    newtree();
    flag=true;
    char s[30];
    for(;;)
    {
        if(scanf("%s",s)!=1) return false;//輸入格式不正確
        if(!strcmp(s,"()")) break;//輸入結束
        int v;
        //(11,LL) s[1]指 11,LL)
        sscanf(&s[1],"%d",&v);//讀入節點值 
        //保存後面的 (11,LL) 保存s[1]保存LL)
        //strchr返回的是從左往右 第一個字符”,“的指針
        addnode(v,strchr(s,,)+1);//添加節點

    }
    return true;
}
    bool bfs() //寬度優先遍歷
    {
        ans.clear();
        queue<int> q;
        q.push(root);
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            if(hv[u]==false) return false;
            ans.push_back(val[u]);
            if(lf[u]!=0) q.push(lf[u]);
            if(rt[u]!=0) q.push(rt[u]);

        }
        return true;
    }
    int main()
    {
       while(input()){
        if(bfs()&&flag){
            for(int i=0;i<ans.size();i++)
            {
                if(i>0) printf(" ");
                printf("%d",ans[i]);
            }
            printf("\n");
        }
        else printf("not complete\n");
       }

    }

總結:

本題是訓練二叉樹的一道好題。首先要解決讀數據問題,根據題意,當輸入為“()”時,結束該組數據讀入,當沒有字符串時,整個輸入結束。因此可以專門編寫一個readin()函數,類型設置為bool型,遇到第一種情況時返回true,遇到第二種情況返回false,主程序中只要發現readin返回false時就break,結束整個大循環。

接下來要建立二叉樹,首先為二叉樹編寫一個結構體,然後根據字符串的輸入情況來建樹,如果是‘L’就往左走,走不動時建一顆新樹,同樣的方法處理右子樹,最後讀入結點值。由於輸入可能有誤,因此用一個全局變量failed來記錄是否有輸入錯誤的情況出現,如果在建樹過程中發現該結點已經被賦過值,那麽全局變量failed變為true。

最後開始BFS找結點值,此時可能出現有結點沒有結點值的情況,因此要把bfs定義為bool型,只要出現這種非法情況,返回false。最後便不難根據情況進行輸出了。

例題6-7 樹的層次遍歷