二叉樹的遍歷

構(gòu)造

//節(jié)點
public class Node {
    public int value;//數(shù)據(jù)
    public Node left;//左節(jié)點
    public Node right;//右節(jié)點
    //構(gòu)造函數(shù)
    Node(int i){
        value = i;
        left=null;
        right=null;
    }
}

二叉樹的構(gòu)造绷杜。
先要有一棵樹直秆,才能遍歷一棵樹。

static void preSet(Node node,Node[] nodes,int i){
    if(i*2+1 < nodes.length) {
        node.left = nodes[i * 2+1];
    }
    if(i*2+2 < nodes.length){
        node.right = nodes[i*2+2];    
    }
}
        Node[] nodes = new Node[13];
        for(int i =0 ;i<13;i++) {
            Node node = new Node(i);
            nodes[i] = node;
        }
        for(int i=0;i<13;i++){
            preSet(nodes[i],nodes,i);
        }

首先構(gòu)造一顆簡單的完全二叉樹


Paste_Image.png

刪去一些節(jié)點:

        nodes[2].right=null;
        nodes[3].left=null;
        nodes[4].right=null;
        nodes[5].left=null;
Paste_Image.png

生成了一棵樹鞭盟,開始遍歷吧圾结。

遍歷

Paste_Image.png

遞歸實現(xiàn)

  • 前序遍歷 => ABC
static void preTravel(Node node){
    if(node==null ){
        return;
    }
    System.out.print(node.value + ",");
    preTravel(node.left);
    preTravel(node.right);
}
  • 中序遍歷 =>BAC
static void preTravel(Node node){
    if(node==null ){
        return;
    }
    preTravel(node.left);
    System.out.print(node.value + ",");
    preTravel(node.right);
}
  • 后續(xù)遍歷 =>BCA
static void preTravel(Node node){
    if(node==null ){
        return;
    }
    preTravel(node.left);
    preTravel(node.right);
    System.out.print(node.value + ",");
}

非遞歸實現(xiàn)

非遞歸實現(xiàn),這里我根據(jù)網(wǎng)上的思路齿诉,用到了棧. (廢話連篇) 其實不用棧也可以筝野,畢竟看到了這個棧我是用ArrayList寫的,所以只要用到棧的這種思路就行了粤剧,不一定一定要寫一個棧歇竟。但是確實棧很方便...
一個簡單的棧:

public class Stack {
    int current=0;
    private ArrayList<Node> nodes = new ArrayList<Node>();
    boolean isEmpty(){
        if(0==current){
            return true; 
       }
        return false;
    }
    void push(Node node){
        if(node==null){
            return;
        }
        nodes.add(node);
        current++;
    }
    Node pop() throws Exception{
        if(isEmpty()){
            throw new Exception();
        }
        current--;        
        return nodes.remove(current);
    }
}
前序遍歷

實現(xiàn)1:

static void preTraverse(Node node)throws Exception{
    if(node==null){
        return;
    }
    Stack s=new Stack();
    s.push(node);
    while (!s.isEmpty()){
        Node item = s.pop();
        System.out.print(item.value + ",");
        s.push(item.right);
        s.push(item.left);
    } 
   System.out.println();
}

這個實現(xiàn)方法不夠好吧。
缺點分析:每次都要先push再pop抵恋』酪椋可不可以必須push才push呢?


實現(xiàn)2:

直接將node=node.left ,而不是每次先push再pop 出來馋记。

static void preTraverse2(Node node)throws Exception{
    if(node==null){
        return;
    }
    Stack s=new Stack();
    while (node !=null ||!s.isEmpty()){
        if(node!=null) {
            System.out.print(node.value + ",");
            s.push(node.right);
            node = node.left;
        }else {
            node = s.pop();
        }
    }
    System.out.println();
}

進一步優(yōu)化:

實現(xiàn)3:

優(yōu)化的地方是号坡,檢查條件懊烤,內(nèi)嵌了一個while( node != null ),使得不必每次只需檢查node != null的時候還檢查了!s.isEmpty()
但是多了個異常捕獲宽堆。因為這樣可能腌紧,棧為空的時候還向棧中取元素。

static void preTraverse3(Node node)throws Exception{
    if(node==null){
        return;
    }
    Stack s=new Stack();
    try {
        while (node != null || !s.isEmpty()) {
            while (node != null) {
                System.out.print(node.value + ",");
                s.push(node.right);
                node = node.left;
            }
            node = s.pop();
        }
    }catch (Exception e){
        ;
    }
    System.out.println();
}

進一步優(yōu)化:
發(fā)現(xiàn)畜隶,
1.只有在pop時候壁肋,在需要檢查棧是否空
2.初始化的時候棧為空,
3.內(nèi)嵌了一個while(node籽慢!=null)浸遗,只有在node為空的時候,才會去棧中獲取元素箱亿,如果獲取不到元素跛锌,那么外圍的while(node!=null)檢查條件依然有效.

實現(xiàn)4:

static void preTraverse4(Node node)throws Exception{
    if(node==null){
        return;
    }
    Stack s=new Stack();
    while (node != null ) {
        while (node != null) {
            System.out.print(node.value + ",");
            s.push(node.right);
            node = node.left;
        }
        if( !s.isEmpty()) {
            node = s.pop();
        }
    }
    System.out.println();
}

進一步優(yōu)化:

實現(xiàn)5:

額届惋,好吧髓帽,節(jié)省了一個的node!=null的檢查而已...

static void preTraverse5(Node node)throws Exception{
    if(node==null){
        return;
    }
    Stack s=new Stack();
    while (node != null ) {
        System.out.print(node.value + ",");
        s.push(node.right);
        node = node.left;
        while (node != null) {
            System.out.print(node.value + ",");
            s.push(node.right);
            node = node.left;
        }
        if( !s.isEmpty()) {
            node = s.pop();
        }
    }
    System.out.println();
}

好了脑豹,我是到此結(jié)束了郑藏。

其他的書寫思路一樣,快速看瘩欺,就直接溜到結(jié)尾的實現(xiàn)中必盖。(多么貼心的boy!)

中序遍歷

實現(xiàn)1:

static void InOrderTraverse(Node node)throws Exception{
    if(node==null){        return;    }
    Stack s=new Stack();
    s.push(node);
    while(!s.isEmpty()){
        node = s.pop();
        //如果左節(jié)點不存在
        if(node.left!=null){
            s.push(node);
            s.push(node.left);
        }else if(node.right!=null){//如果右節(jié)點不存在
            System.out.print(node.value+",");
            s.push(node.right);
        }else{//其他的情況俱饿,那就是沒有節(jié)點嘛
            System.out.print(node.value+",");
            node = s.pop();
            while(node.right==null){
                System.out.print(node.value+",");
                if(!s.isEmpty()) {
                    node = s.pop();//獲取父親節(jié)點
                }else{
                    return;
                }
            }
            System.out.print(node.value+",");
            s.push(node.right);
        }
    }
}

這個代碼看起來就很頭大歌粥,本人寫的,自己都看不下去..也是調(diào)試后寫出來的稍途。不管了阁吝。優(yōu)化。


實現(xiàn)2:

主要是不要非得將節(jié)點放入棧械拍,再拿出這種浪費效率的工作突勇。而是直接node=node.left;node=node.right;

//BACstatic void InOrderTraverse3(Node node)throws Exception{
    if(node==null){
        return;
    }
    Stack s=new Stack();
    while(node!=null || !s.isEmpty()){
        if(node.left!=null){//如果左節(jié)點不為空
            s.push(node);
            node = node.left;
        }else if(node.right!=null){//如果右節(jié)點不為空
            System.out.print(node.value + ",");
            node =node.right;
        }else {//否則就是都是空
            System.out.print(node.value + ",");
            node = s.pop();//獲取父親節(jié)點
            while(node.right==null){
                System.out.print(node.value + ",");
                if(!s.isEmpty()) {
                    node = s.pop();
                }else{
                    return;
                }
            }
            System.out.print(node.value + ",");
            node=node.right;
        }
    }
}

實現(xiàn)3:

這里其實并沒有優(yōu)化,而是合并了下代碼坷虑。

static void InOrderTraverse4(Node node)throws Exception{
    if(node==null){
        return;
    }
    Stack s=new Stack();
    while(node!=null || !s.isEmpty()){
        if(node.left!=null){
            s.push(node);
            node = node.left;
        }else if(node.right!=null){
            System.out.print(node.value + ",");
            node =node.right;
        }else {
            while (node.right == null) {
                System.out.print(node.value + ",");
                if(!s.isEmpty()) {
                    node = s.pop();
                }else{
                    return;
                }
            }
            System.out.print(node.value + ",");
            node=node.right;
        }
    }
}

實現(xiàn)4:

發(fā)現(xiàn)其實第二個else if 中的操作了甲馋,else中的操作其實是一致的,可以合并:

static void InOrderTraverse6(Node node)throws Exception{
    if(node==null){
        return;
    }
    Stack s=new Stack();
    while(node!=null || !s.isEmpty()){
        while(node.left!=null){
            s.push(node);
            node = node.left;
        }
        while(node.right == null){
            System.out.print(node.value + ",");
            if(!s.isEmpty()) {
                node = s.pop();
            }else{
                return;
            }
        }
        System.out.print(node.value + ",");
        node = node.right;
    }
}

實現(xiàn)5:

其實是把后半部分的代碼移動了一下而已...

static void InOrderTraverse7(Node node)throws Exception{
    if(node==null){        return;    }
    Stack s=new Stack();
    while(node!=null || !s.isEmpty()){
        while(node.left!=null){
            s.push(node);
            node = node.left;
        }
        System.out.print(node.value + ",");
        node=node.right;
        while(node ==null){
            if(!s.isEmpty()) {
                node = s.pop();
                System.out.print(node.value + ",");
                node=node.right;
            }else{return;}
        }
    }
}

實現(xiàn)6:

又是換了下代碼的位置而已迄损,其實是想少一個while定躏,想利用外面的while,本來就要檢查!s.isEmpty

static void InOrderTraverse8(Node node)throws Exception{
    if(node==null){
        return;
    }
    Stack s=new Stack();
    while(node!=null || !s.isEmpty()){
        if(node==null){
            node=s.pop();
            System.out.print(node.value + ",");
            node=node.right;
        }else {
            while (node.left != null) {
                s.push(node);
                node = node.left;
            }
            System.out.print(node.value + ",");
            node = node.right;
        }
    }
}

實現(xiàn)7:

這個優(yōu)化痊远,有點明顯的垮抗,額。
1.上面步驟中碧聪,else部分冒版,的下半部分,其實操作和if的下半部分一樣
2.else中上面是push逞姿。if中有個pop

static void InOrderTraverse10(Node node)throws Exception{
    if(node==null){        return;    }
    Stack s=new Stack();
    while(node!=null || !s.isEmpty()){
        if(node==null){
            node=s.pop();
            System.out.print(node.value + ",");
            node=node.right;
        }else{
            while (node.left != null) {
                s.push(node);
                node = node.left;
            }
            s.push(node);
        }
    }
}

實現(xiàn)8:

無論如何s.push(node)這個操作都會被執(zhí)行辞嗡。所以:

static void InOrderTraverse9(Node node)throws Exception{
    if(node==null){
        return;
    }
    Stack s=new Stack();
    while(node!=null || !s.isEmpty()){
        if(node==null){
            node=s.pop();
            System.out.print(node.value + ",");
            node=node.right;
        }else{
            s.push(node);
            node = node.left;
        }
    }
}

實現(xiàn)9:

網(wǎng)友的實現(xiàn),我就是因為網(wǎng)友這個刺激的呀滞造,所以一步步實現(xiàn)優(yōu)化续室。
這里又把檢測條件縮小了一下。

static void InOrderTraverse2(Node node)throws Exception{
    if(node==null){        return;    }
    Stack s=new Stack();
    while( node!=null || !s.isEmpty()){
        while(node!=null){
            s.push(node);
            node = node.left;
        }
        node = s.pop();
        System.out.print(node.value+",");
        node=node.right;
    }
}

后序遍歷

實現(xiàn)1:

static void postTraverse(Node node)throws Exception{
    if(node==null){        return;    }
    Stack s = new Stack();
    s.push(node);
    while (!s.isEmpty()){
        node = s.pop();
        if(node.left==null && node.right==null){
            System.out.print(node.value + ",");
            Node node1 =s.pop();
            while(node1.left == node || node1.right == node){
                System.out.print(node1.value+",");
                node = node1;
                try{
                    node1=s.pop();
                }catch (Exception e){
                    return;
                }
            }
            s.push(node1);
        }else {
            s.push(node);
            s.push(node.right); 
           s.push(node.left);
        }
    }
}

實現(xiàn)2:

主要是
1.簡化了pop和push操作谒养,將操作變簡單

static void postTraverse2(Node node)throws Exception{
    if(node==null){        return;    }
    Stack s = new Stack();
    try {
        while (node != null || !s.isEmpty()) {
            if(node==null){
                node =s.pop();
            }
            if (node.left == null && node.right == null) {
                System.out.print(node.value + ",");
                Node node1 = s.pop();//獲取父節(jié)點
                while (node1.left == node || node1.right == node) {//檢查是不是父節(jié)點
                    System.out.print(node1.value + ",");
                    node = node1;
                    node1 = s.pop();
                }
                node=node1;
            } else {
                s.push(node);
                s.push(node.right);
                node = node.left;
            }
        }
    }catch (Exception e){
        return;
    }
    System.out.println();
}

實現(xiàn)3:

并沒有實質(zhì)性的優(yōu)化...

static void postTraverse3(Node node)throws Exception{
    if(node==null){        return;    }
    Stack s = new Stack();
    try {
        while (node != null || !s.isEmpty()) {
            if(node==null){
                node =s.pop();
            }
            if (node.left == null && node.right == null) {
                System.out.print(node.value + ",");
                Node tmp=node;
                node = s.pop();//獲取父節(jié)點
                while (node.left == tmp || node.right == tmp) {//檢查是不是父節(jié)點
                    System.out.print(node.value + ",");
                    tmp = node;
                    node = s.pop();
                }
            } else {
                s.push(node);
                s.push(node.right);
                node = node.left;
            }
        }
    }catch (Exception e){
        return;
    }
}

實現(xiàn)4:

static void postTraverse4(Node node)throws Exception{
    if(node==null){
        return;    }
    Stack s = new Stack();
    try {
        while (node != null || !s.isEmpty()) {
            if (node.left == null && node.right == null) {
                Node tmp;
                do {
                    System.out.print(node.value + ",");
                    tmp = node;
                    node = s.pop();//獲取父節(jié)點
                }while (node.left == tmp || node.right == tmp);//檢查是不是父節(jié)點
            }else {
                s.push(node);
                s.push(node.right);
                node = node.left;
                if(node==null){
                    node =s.pop();
                }
            } 
       }
    }catch (Exception e){
        return;
    }
}



實現(xiàn)5:

網(wǎng)友的思路是:
設(shè)置標志位挺狰,如果讀取過一次就置1.不然,就設(shè)置0.
就是Stack中他添加了一個tag數(shù)組买窟,用于設(shè)置其標志位她渴。
void postorder_dev(bintree t){
    seqstack s;
    s.top = -1;
    if(!t){
        printf("the tree is empty!\n");
    }else{
        while(t || s.top != -1){    //棧空了的同時t也為空蔑祟。
            while(t){
                push(&s,t);
                s.tag[s.top] = 0;   //設(shè)置訪問標記,0為第一次訪問沉唠,1為第二次訪問
                t= t->lchild;
            }
            if(s.tag[s.top] == 0){  //第一次訪問時疆虚,轉(zhuǎn)向同層右結(jié)點
                t= s.data[s.top];   //左走到底時t是為空的,必須有這步满葛!
                s.tag[s.top]=1;     
                t=t->rchild;
            }else {
                while (s.tag[s.top] == 1){ //找到棧中下一個第一次訪問的結(jié)點径簿,退出循環(huán)時并沒有pop所以為其左子結(jié)點
                    t = pop(&s);
                    printf("%c ",t->data);
                }
                t = NULL; //必須將t置空。跳過向左走嘀韧,直接向右走
            }
        }
    }
}
層級遍歷
static void levelTravel(Node node){
    if(node==null){
        return;
    }
    ArrayList<Node> nodes= new ArrayList<Node>();
    nodes.add(node);
    while(!nodes.isEmpty()){
        Node item = nodes.remove(0);
        if(item==null){
            continue;
        }
        System.out.println(item.value);
        nodes.add(item.left);
        nodes.add(item.right);
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末篇亭,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子锄贷,更是在濱河造成了極大的恐慌译蒂,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谊却,死亡現(xiàn)場離奇詭異柔昼,居然都是意外死亡,警方通過查閱死者的電腦和手機炎辨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進店門捕透,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事乙嘀∧┕海” “怎么了?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵虎谢,是天一觀的道長盟榴。 經(jīng)常有香客問我,道長嘉冒,這世上最難降的妖魔是什么曹货? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮讳推,結(jié)果婚禮上顶籽,老公的妹妹穿的比我還像新娘。我一直安慰自己银觅,他們只是感情好礼饱,可當我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著究驴,像睡著了一般镊绪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上洒忧,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天蝴韭,我揣著相機與錄音,去河邊找鬼熙侍。 笑死榄鉴,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的蛉抓。 我是一名探鬼主播庆尘,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼巷送!你這毒婦竟也來了驶忌?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤笑跛,失蹤者是張志新(化名)和其女友劉穎付魔,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體飞蹂,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡抒抬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了晤柄。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片擦剑。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出惠勒,到底是詐尸還是另有隱情赚抡,我是刑警寧澤,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布纠屋,位于F島的核電站涂臣,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏售担。R本人自食惡果不足惜赁遗,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望族铆。 院中可真熱鬧岩四,春花似錦、人聲如沸哥攘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽逝淹。三九已至耕姊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間栅葡,已是汗流浹背茉兰。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留欣簇,地道東北人邦邦。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像醉蚁,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子鬼店,可洞房花燭夜當晚...
    茶點故事閱讀 44,652評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 面試中經(jīng)常會考的一道題目网棍,就是二叉樹的遍歷,很簡單妇智,你會說“使用遞歸滥玷,根據(jù)要求(前序、中序巍棱、后序惑畴,以中序為例)依次...
    _CloudNine閱讀 274評論 1 1
  • -先序遍歷: 訪問根結(jié)點,先序遍歷其左子樹航徙,先序遍歷其右子樹如贷;運用到遞歸void PreOrderTraversa...
    Spicy_Crayfish閱讀 2,028評論 0 0
  • 二叉樹的遍歷想必大家都不陌生,主要有三種遍歷方式:前序遍歷(pre-order traversal),中序遍歷(i...
    akak18183閱讀 1,115評論 0 1
  • 二叉樹的三種常用遍歷方式 學習過數(shù)據(jù)結(jié)構(gòu)的同學都清楚杠袱,除了層序遍歷外尚猿,二叉樹主要有三種遍歷方式: 1. 先序遍歷...
    SherlockBlaze閱讀 1,230評論 0 4
  • 文章來源https://segmentfault.com/a/1190000000740261 基本性質(zhì) 每個節(jié)點...
    vinson_sheep閱讀 278評論 0 0