最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java二叉樹的四種遍歷(遞歸和非遞歸)

 更新時(shí)間:2020年12月04日 19:15:56   作者:燈塔先生  
這篇文章主要介紹了Java二叉樹的四種遍歷,二叉樹的遍歷可以分為前序、中序、后序、層次遍歷,需要的朋友可以參考下

二叉樹的遍歷可以分為前序、中序、后序、層次遍歷。

前中后是指何時(shí)訪問中間節(jié)點(diǎn),即前序遍歷,遍歷節(jié)點(diǎn)的順序?yàn)椋褐小?gt;左—>右;

中序遍歷,遍歷節(jié)點(diǎn)的順序?yàn)椋鹤蟆?gt;中—>右;

后序遍歷,遍歷節(jié)點(diǎn)的順序?yàn)椋鹤蟆?gt;右—>中。

前序遍歷

遞歸實(shí)現(xiàn)

public void preorder_Traversal(TreeNode root)
  {
    if(root==null)return;
    
    //訪問節(jié)點(diǎn)的邏輯代碼塊
    System.out.print(root.val+" ");
    
    preorder_Traversal(root.left);
    preorder_Traversal(root.right);
  }

非遞歸過程如下:

1.每遍歷一個(gè)節(jié)點(diǎn)的時(shí)候,先節(jié)點(diǎn)入棧,然后尋找當(dāng)前節(jié)點(diǎn)的左子節(jié)點(diǎn)。(因?yàn)槭乔靶虮闅v,所以在節(jié)點(diǎn)入棧之前就可以對(duì)節(jié)點(diǎn)進(jìn)行訪問)

2.當(dāng)某個(gè)節(jié)點(diǎn)的左子節(jié)點(diǎn),當(dāng)左子節(jié)點(diǎn)不為空的時(shí)候,重復(fù)過程1.

3.當(dāng)左子節(jié)點(diǎn)為空的時(shí)候?qū)?dāng)前節(jié)點(diǎn)出棧,并且通過其尋找右子節(jié)點(diǎn),右子節(jié)點(diǎn)不為空的時(shí)候,重復(fù)過程1-2

4.當(dāng)右子節(jié)點(diǎn)也為空的時(shí)候,則跳回上一個(gè)該節(jié)點(diǎn)的父節(jié)點(diǎn)(即因?yàn)楫?dāng)前節(jié)點(diǎn)已經(jīng)出棧,所以現(xiàn)在在棧中最上層的節(jié)點(diǎn)是當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn))

非遞歸實(shí)現(xiàn)

public void preorder(TreeNode root)
  {
    Stack<TreeNode>  stack=new Stack<>();
    while(root!=null||!stack.isEmpty())
    {
      //當(dāng)前節(jié)點(diǎn)不為空,則入棧,確保最后遍歷到的節(jié)點(diǎn)沒有左子節(jié)點(diǎn)
      //因?yàn)槭乔靶虮闅v,所以再遍歷到每個(gè)節(jié)點(diǎn)的時(shí)候,都可以先訪問,再尋找其左右子節(jié)點(diǎn)。
      while(root!=null)
      {
        System.out.print(root.val+" ");
        stack.push(root);
        root=root.left;
      }
      if(!stack.empty())
      {
        //把這兩步看成是一步,找到右節(jié)點(diǎn),并把已處理的中節(jié)點(diǎn)從stack當(dāng)中去除
        root=stack.pop();
        root=root.right;
      }
    }
  }

中序遍

遞歸實(shí)現(xiàn)

public void inorder_Traversal(TreeNode root)
  {
    if(root==null)return;
    inorder_Traversal(root.left);
    
     //訪問節(jié)點(diǎn)的邏輯代碼塊
    System.out.print(root.val+" ");
    
    inorder_Traversal(root.right);
  }

非遞歸

對(duì)比前序、中序,發(fā)現(xiàn)代碼幾乎一模一樣,但唯一的不同的是,訪問節(jié)點(diǎn)的位置不一樣,中序遍歷是當(dāng)左子節(jié)點(diǎn)被訪問過,或者不存在的時(shí)候,才可以訪問中間節(jié)點(diǎn),所以再該處,訪問節(jié)點(diǎn)的位置放在了當(dāng)左子節(jié)點(diǎn)不存在的時(shí)候,即節(jié)點(diǎn)出棧的時(shí)候,即是左子節(jié)點(diǎn)不存在的時(shí)候進(jìn)行訪問。

非遞歸實(shí)現(xiàn)

public void Inorder(TreeNode root)
  {
    Stack<TreeNode> stack=new Stack<>();
    while(root!=null||!stack.isEmpty())
    {
      //當(dāng)前節(jié)點(diǎn)不為空,則入棧,確保最后遍歷到的節(jié)點(diǎn)沒有左子節(jié)點(diǎn)
      while(root!=null)
      {
        stack.push(root);
        root=root.left;
      }
      //通過當(dāng)前節(jié)點(diǎn),跳到當(dāng)前節(jié)點(diǎn)的右節(jié)點(diǎn),因?yàn)槭侵行虮闅v,所以當(dāng)前節(jié)點(diǎn)沒有左節(jié)點(diǎn)的時(shí)候,就 
       可以訪問當(dāng)前節(jié)點(diǎn)
      if(!stack.empty())
      {
        root=stack.pop();
        System.out.print(root.val+" ");
        root=root.right;
      }
    }
  }

后序遍歷

遞歸實(shí)現(xiàn)

public void postorder_Traversal(TreeNode root)
  {
    if(root==null)return;
    postorder_Traversal(root.left);
    postorder_Traversal(root.right);
    
     //訪問節(jié)點(diǎn)的邏輯代碼塊
    System.out.print(root.val+" ");
  }

非遞歸版本一

借助兩個(gè)棧來存儲(chǔ)我們的節(jié)點(diǎn)以及標(biāo)示位,過程如下:

1.每遍歷一個(gè)節(jié)點(diǎn)的時(shí)候,先節(jié)點(diǎn)入棧s,并且s2入棧一個(gè)標(biāo)識(shí)位0,然后尋找當(dāng)前節(jié)點(diǎn)的左子節(jié)點(diǎn)。

2.當(dāng)某個(gè)節(jié)點(diǎn)的左子節(jié)點(diǎn),當(dāng)左子節(jié)點(diǎn)不為空的時(shí)候,重復(fù)過程1.

3.當(dāng)左子節(jié)點(diǎn)為空的時(shí)候?qū)?dāng)前節(jié)點(diǎn)peek出(即將節(jié)點(diǎn)拿出,但棧中還是有該節(jié)點(diǎn)),并且此時(shí)將s2對(duì)應(yīng)棧頂?shù)臉?biāo)識(shí)位改為1,通過其尋找右子節(jié)點(diǎn),右子節(jié)點(diǎn)不為空的時(shí)候,重復(fù)過程1-2

4.當(dāng)右子節(jié)點(diǎn)也為空的時(shí)候,并且s2對(duì)應(yīng)的標(biāo)識(shí)符為1的時(shí)候,則彈出s1棧頂?shù)漠?dāng)前節(jié)點(diǎn),并且將s2的標(biāo)識(shí)符彈出(即因?yàn)楫?dāng)前節(jié)點(diǎn)還沒有出棧,所以現(xiàn)在在棧中最上層的節(jié)點(diǎn)是當(dāng)前節(jié)),注意s1彈出當(dāng)前節(jié)點(diǎn)并訪問,但是不賦值給root,在這個(gè)root此時(shí)還是null

5.進(jìn)入過程3,此時(shí)root被peek賦值到當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)(因?yàn)樵谶^程4當(dāng)中,已經(jīng)pop出了當(dāng)前節(jié)點(diǎn),所以s1棧頂是當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn))的右子節(jié)點(diǎn)。

6.重復(fù)過程1-5

public void Postorder(TreeNode root)
  {
    Stack<TreeNode> s =new Stack<>(); 
    Stack<Integer> s2 =new Stack<>();
    Integer i=new Integer(1);
    while(root!=null||!s.isEmpty())
    {
      //只要當(dāng)前節(jié)點(diǎn)非空,就入棧
      while(root!=null)
      {
        s.push(root);
        s2.push(new Integer(0));
        root=root.left;
      }
      //s2當(dāng)中如果存1,則意味著當(dāng)前s1對(duì)應(yīng)的節(jié)點(diǎn)的左右子節(jié)點(diǎn)都已經(jīng)遍歷過了。
      while(!s.empty()&&s2.peek().equals(i))
      {
        s2.pop();
        System.out.print(s.pop().val+" ");
      }
      if(!s.isEmpty())
      {
        s2.pop();
        s2.push(new Integer(1));
        root=s.peek();
        root=root.right;
      }
      
    }
  }

非遞歸版本二

實(shí)現(xiàn)思路:

在進(jìn)行后序遍歷的時(shí)候是先要遍歷左子樹,然后在遍歷右子樹,最后才遍歷根節(jié)點(diǎn)。所以在非遞歸的實(shí)現(xiàn)中要先把根節(jié)點(diǎn)入棧,然后再把左子樹入棧直到左子樹為空,此時(shí)停止入棧。此時(shí)棧頂就是需要訪問的元素,所以直接取出訪問p。在訪問結(jié)束后,還要判斷被訪問的節(jié)點(diǎn)p是否為棧頂節(jié)點(diǎn)的左子樹,如果是的話那么還需要訪問棧頂節(jié)點(diǎn)的右子樹,所以將棧頂節(jié)點(diǎn)的右子樹取出賦值給p。如果不是的 話則說明棧頂節(jié)點(diǎn)的右子樹已經(jīng)訪問完了,那么現(xiàn)在可以訪問棧頂節(jié)點(diǎn)了,所以此時(shí)將p賦值為null。判斷結(jié)束的條件是p不為空或者棧不為空,若果兩個(gè)條件都不滿足的話,說明所有節(jié)點(diǎn)都已經(jīng)訪問完成。

非遞歸實(shí)現(xiàn)

public void postOrder(Node root) {
		
	Stack<Node> s = new Stack<Node>();
	Node p = root;
	while (p != null || !s.empty()) {
		while(p != null) {
			s.push(p);
			p = p.left;
		}
		p = s.pop();
		System.out.print(p.val+" ");
	//這里需要判斷一下,當(dāng)前p是否為棧頂?shù)淖笞訕?,如果是的話那么還需要先訪問右子樹才能訪問根節(jié)點(diǎn)
	//如果已經(jīng)是不是左子樹的話,那么說明左右子書都已經(jīng)訪問完畢,可以訪問根節(jié)點(diǎn)了,所以講p復(fù)制為NULL
	//取根節(jié)點(diǎn)
		if (!s.empty() && p == s.peek().left) {
			p = s.peek().right;
		}
		else p = null;
	}
}
 

層次遍歷

用隊(duì)列實(shí)現(xiàn),步驟是:

1.對(duì)于不為空的結(jié)點(diǎn),先把該結(jié)點(diǎn)加入到隊(duì)列中;

2.從隊(duì)中拿出結(jié)點(diǎn),如果該結(jié)點(diǎn)的左右結(jié)點(diǎn)不為空,就分別把左右結(jié)點(diǎn)加入到隊(duì)列中;

3.重復(fù)以上操作直到隊(duì)列為空;

public void LaywerTraversal(TreeNode root){
  if(root==null) return;
  LinkedList<TreeNode> list = new LinkedList<TreeNode>(); 
  list.add(root);
  TreeNode currentNode;
  while(!list.isEmpty()){
    currentNode=list.poll();
    System.out.println(currentNode.val);
    if(currentNode.left!=null){
      list.add(currentNode.left);
    }
    if(currentNode.right!=null){
      list.add(currentNode.right);
    }
  }
}

到此這篇關(guān)于Java二叉樹的四種遍歷(遞歸和非遞歸)的文章就介紹到這了,更多相關(guān)Java二叉樹內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • idea中springboot項(xiàng)目連接數(shù)據(jù)庫報(bào)錯(cuò)的原因解析

    idea中springboot項(xiàng)目連接數(shù)據(jù)庫報(bào)錯(cuò)的原因解析

    這篇文章主要介紹了idea中springboot項(xiàng)目連接數(shù)據(jù)庫報(bào)錯(cuò)的原因解析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12
  • Java設(shè)計(jì)模式之模版方法模式簡(jiǎn)介

    Java設(shè)計(jì)模式之模版方法模式簡(jiǎn)介

    這篇文章主要介紹了Java設(shè)計(jì)模式之模版方法模式,需要的朋友可以參考下
    2014-07-07
  • Java批量操作文件系統(tǒng)的實(shí)現(xiàn)示例

    Java批量操作文件系統(tǒng)的實(shí)現(xiàn)示例

    文件上傳和下載是java web中常見的操作,本文主要介紹了Java批量操作文件系統(tǒng)的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-03-03
  • 淺談maven 多環(huán)境打包發(fā)布的兩種方式

    淺談maven 多環(huán)境打包發(fā)布的兩種方式

    這篇文章主要介紹了淺談maven 多環(huán)境打包發(fā)布的兩種方式,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-08-08
  • 解決在for循環(huán)中remove list報(bào)錯(cuò)越界的問題

    解決在for循環(huán)中remove list報(bào)錯(cuò)越界的問題

    這篇文章主要介紹了解決在for循環(huán)中remove list報(bào)錯(cuò)越界的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • 最新評(píng)論

    嘉峪关市| 新昌县| 涿州市| 兴城市| 三亚市| 通河县| 昌吉市| 克山县| 荣成市| 平遥县| 镇赉县| 江门市| 甘德县| 台南市| 策勒县| 竹北市| 子洲县| 长白| 盐城市| 桑植县| 错那县| 县级市| 西乌珠穆沁旗| 松江区| 永修县| 明溪县| 南昌县| 阿拉善右旗| 毕节市| 镇平县| 耒阳市| 苏尼特左旗| 额尔古纳市| 宁安市| 新沂市| 咸阳市| 民县| 邹城市| 车险| 华池县| 兰西县|