Java?數(shù)據(jù)結(jié)構(gòu)進(jìn)階二叉樹題集下
1、對稱二叉樹
分為以下幾種情況:
- 二叉樹為空,是對稱二叉樹
- 二叉樹不為空,其左子樹或者右子樹為空,不是對稱二叉樹
- 二叉樹不為空,左右子樹都為空,是對稱二叉樹
- 二叉樹不為空,左右子樹不為空,左右子節(jié)點(diǎn)值不同,不是對稱二叉樹
- 二叉樹不為空,左右子樹不為空,左右子節(jié)點(diǎn)值相同,如果左子樹的左節(jié)點(diǎn)和右子樹的右節(jié)點(diǎn)、左子樹的右節(jié)點(diǎn)和右子樹的左節(jié)點(diǎn)相同,則其為對稱二叉樹,否則,不是對稱二叉樹。
【代碼如下】
class Solution { public boolean isSymmetric(TreeNode root) { if(root==null){ return true; } return isSymmetricChild(root.left,root.right); } public boolean isSymmetricChild(TreeNode left,TreeNode right){ if(left==null&&right==null){ return true; } if(left==null||right==null){ return false; } if(left.val!=right.val){ return false; } return isSymmetricChild(left.left,right.right)&&isSymmetricChild(left.right,right.left); } }
2、創(chuàng)建并遍歷二叉樹
【題目描述】
讀入用戶輸入的一串先序遍歷字符串,根據(jù)此字符串建立一個(gè)二叉樹(以指針方式存儲(chǔ))。 例如如下的先序遍歷字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空樹。建立起此二叉樹以后,再對二叉樹進(jìn)行中序遍歷,輸出遍歷結(jié)果。
關(guān)于這個(gè)題,完全從零開始,我們需要定義(1)二叉樹的節(jié)點(diǎn),(2)中序遍歷的函數(shù),(3)根據(jù)先序遍歷字符串創(chuàng)建二叉樹的函數(shù),(4)主函數(shù)。創(chuàng)建節(jié)點(diǎn)、中序遍歷、主函數(shù)不用多說。主要說一下根據(jù)先序遍歷字符串來創(chuàng)建二叉樹的過程:
遍歷字符串,#表示空,就分為以下兩種情況:如果字符不為空,我們需要?jiǎng)?chuàng)建根節(jié)點(diǎn),然后遞歸創(chuàng)建其的左右子樹;否則,直接跳過即可。
【代碼如下】
import java.util.Scanner; //定義二叉樹的節(jié)點(diǎn) class TreeNode{ public char val; public TreeNode left; public TreeNode right; public TreeNode(char val){ this.val=val; } } public class Main { //根據(jù)先序遍歷字符串創(chuàng)建二叉樹 public static int i=0; public static TreeNode createTree(String s){ TreeNode root=null; //字符不為空的情況下,創(chuàng)建根節(jié)點(diǎn) if(s.charAt(i)!='#'){ root=new TreeNode(s.charAt(i)); i++; //遞歸創(chuàng)建root的左右子樹 root.left=createTree(s); root.right=createTree(s); }else{ //字符為空,直接跳過 i++; } return root; } public static void inorderTree(TreeNode root){ if(root==null){ return; } inorderTree(root.left); System.out.print(root.val+" "); inorderTree(root.right); } //中序遍歷二叉樹 public static void main(String[] args) { Scanner in = new Scanner(System.in); while (in.hasNextLine()){ String s=in.nextLine(); TreeNode node=createTree(s); inorderTree(node); } } }
3、二叉樹中兩節(jié)點(diǎn)最近公共祖先
二叉樹的根節(jié)點(diǎn)為root,以及兩個(gè)節(jié)點(diǎn)p、q,如果二叉樹為空,則返回null;如果二叉樹的根節(jié)點(diǎn)等于p或者q,或者p、q在根節(jié)點(diǎn)的左右兩側(cè),則其最近公共結(jié)點(diǎn)為root;如果p、q系欸但在root節(jié)點(diǎn)的同側(cè),則最小公共結(jié)點(diǎn)就是該側(cè)的節(jié)點(diǎn)。
【代碼如下】
class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { if(root==null){ return null; } if(root==q||root==p){ return root; } TreeNode left=lowestCommonAncestor(root.left,p,q); TreeNode right=lowestCommonAncestor(root.right,p,q); if(left==null){ return right; } if(right==null){ return left; } return root; } }
4、二叉搜索樹與雙向鏈表
二叉搜索樹:任何節(jié)點(diǎn)的左子樹小于右子樹
將二叉搜索樹轉(zhuǎn)換為有序的雙向鏈表:
二叉搜索樹的中序遍歷結(jié)果為有序的。所以我們只需要寫一個(gè)中序遍歷,在其中實(shí)現(xiàn)其節(jié)點(diǎn)左右指向的改變即可。首先我們需要一個(gè)前驅(qū)節(jié)點(diǎn)prev來保存每個(gè)節(jié)點(diǎn)的左節(jié)點(diǎn),初始為null,因?yàn)槭请p向鏈表,所以prev還需要指向它的右節(jié)點(diǎn),如果其為空,則不用。
【代碼如下】
public class Solution { public TreeNode prev=null; //中序遍歷二叉樹 public void inorderTree(TreeNode root){ if(root==null){ return ; } inorderTree(root.left); //處理二叉樹的左右節(jié)點(diǎn) root.left=prev; if(prev!=null){ prev.right=root; } prev=root; inorderTree(root.right); } public TreeNode Convert(TreeNode pRootOfTree) { if(pRootOfTree==null){ return null; } inorderTree(pRootOfTree); while(pRootOfTree.left!=null){ pRootOfTree=pRootOfTree.left; } return pRootOfTree; } }
5、根據(jù)前序和中序遍歷結(jié)果創(chuàng)建二叉樹
給出一個(gè)二叉樹的前序遍歷和中序遍歷的結(jié)果,根據(jù)其創(chuàng)建二叉樹:
我們知道,前序遍歷的第一個(gè)元素(prev)一定是根節(jié)點(diǎn)(從前往后遍歷),所以在中序遍歷中找到prev,則左邊元素為左子樹元素,右邊元素為右子樹,創(chuàng)建根節(jié)點(diǎn),遞歸創(chuàng)建左子樹和右子樹。注意一定要先創(chuàng)建左子樹,因?yàn)橄刃虮闅v的因素,先序遍歷數(shù)組的下一個(gè)元素一定是左子樹的根節(jié)點(diǎn)?!救绻歉鶕?jù)后序遍歷和中序遍歷創(chuàng)建二叉樹,則后序遍歷的數(shù)組需要從后往前遍歷,還有,一定要先遞歸創(chuàng)建右子樹】
【代碼如下】
class Solution { public int prevIndex=0; //找到preorder的prevIndex下標(biāo)元素在inorder中的位置 public int findIndex(int[] preorder,int[] inorder,int inbegin,int inend){ for(int i=inbegin;i<=inend;++i){ if(inorder[i]==preorder[prevIndex]){ return i; } } return -1; } //創(chuàng)建二叉樹 public TreeNode buildTreeChild(int[] preorder,int[] inorder,int inbegin,int inend){ if(inbegin>inend){ return null; } TreeNode root=new TreeNode(preorder[prevIndex]); int index=findIndex(preorder,inorder,inbegin,inend); prevIndex++; root.left=buildTreeChild(preorder,inorder,inbegin,index-1); root.right=buildTreeChild(preorder,inorder,index+1,inend); return root; } public TreeNode buildTree(int[] preorder, int[] inorder) { return buildTreeChild(preorder,inorder,0,inorder.length-1); } }
6、二叉樹創(chuàng)建字符串
字符串拼接,可以創(chuàng)建StringBuilder方便拼接,先將根節(jié)點(diǎn)拼接入字符串,如果其左子樹不為空,拼接左括號,遞歸左子樹,遞歸完后拼接右括號;左樹為空的情況下,如果右樹也為空,直接拼接右括號,否則,我們拼接空括號,遞歸右子樹,之后再拼接右括號。
【代碼如下】
class Solution { public void tree2strChild(TreeNode root,StringBuilder str){ if(root==null){ return; } str.append(root.val); if(root.left!=null){ str.append("("); tree2strChild(root.left,str); str.append(")"); }else{ if(root.right==null){ return; }else{ str.append("()"); } } if(root.right==null){ return; }else{ str.append("("); tree2strChild(root.right,str); str.append(")"); } } public String tree2str(TreeNode root) { StringBuilder str=new StringBuilder(); tree2strChild(root,str); return str.toString(); } }
7、非遞歸實(shí)現(xiàn)二叉樹前序遍歷
可以用棧來實(shí)現(xiàn)。定義一個(gè)棧,將根節(jié)點(diǎn)入棧后,去入棧左節(jié)點(diǎn)、左節(jié)點(diǎn)的左節(jié)點(diǎn)……直到為空,去除棧頂元素,入棧其右節(jié)點(diǎn),知道為空,以此循環(huán)即可。(中序遍歷和前序遍歷思路相同)
【代碼如下】
class Solution { public List<Integer> preorderTraversal(TreeNode root) { List<Integer> list=new ArrayList<>(); Stack<TreeNode> stack=new Stack<>(); TreeNode cur=root; while(cur!=null||!stack.empty()){ while(cur!=null){ stack.push(cur); list.add(cur.val); cur=cur.left; } TreeNode node=stack.pop(); cur=node.right; } return list; } }
8、非遞歸實(shí)現(xiàn)二叉樹后序遍歷
初始化一個(gè)空棧。當(dāng)【根節(jié)點(diǎn)不為空】或者【棧不為空】時(shí),從根節(jié)點(diǎn)開。每次將當(dāng)前節(jié)點(diǎn)壓入棧中,如果當(dāng)前節(jié)點(diǎn)有左子樹,就往左子樹跑,沒有左子樹就往右子樹跑。若當(dāng)前節(jié)點(diǎn)無左子樹也無右子樹,從棧中彈出該節(jié)點(diǎn),如果當(dāng)前節(jié)點(diǎn)是上一個(gè)節(jié)點(diǎn)(即彈出該節(jié)點(diǎn)后的棧頂元素)的左節(jié)點(diǎn),嘗試訪問上個(gè)節(jié)點(diǎn)的右子樹,如果不是,那當(dāng)前棧的棧頂元素繼續(xù)彈出。
【代碼如下】
class Solution { public List<Integer> postorderTraversal(TreeNode root) { List<Integer> list=new ArrayList<>(); Stack<TreeNode> stack=new Stack<>(); TreeNode cur=root; TreeNode prev=null; while(cur!=null||!stack.empty()){ while(cur!=null){ stack.push(cur); cur=cur.left; } TreeNode top=stack.peek(); if(top.right==null||top.right==prev){ list.add(top.val); stack.pop(); prev=top; }else{ cur=top.right; } } return list; } }
到此這篇關(guān)于Java 數(shù)據(jù)結(jié)構(gòu)進(jìn)階二叉樹題集下的文章就介紹到這了,更多相關(guān)Java 二叉樹內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java pom.xml parent引用報(bào)錯(cuò)問題解決方案
這篇文章主要介紹了Java pom.xml parent引用報(bào)錯(cuò)問題解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08java實(shí)現(xiàn)word文檔轉(zhuǎn)pdf并添加水印的方法詳解
這篇文章主要介紹了java實(shí)現(xiàn)word文檔轉(zhuǎn)pdf并添加水印的方法,結(jié)合實(shí)例形式詳細(xì)分析了java word文檔轉(zhuǎn)PDF相關(guān)實(shí)現(xiàn)技巧與操作注意事項(xiàng),需要的朋友可以參考下2019-09-09springboot開發(fā)flowable定時(shí)任務(wù)問題
這篇文章主要介紹了springboot開發(fā)flowable定時(shí)任務(wù)問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11解決JAVA遍歷List集合,刪除數(shù)據(jù)時(shí)出現(xiàn)的問題
這篇文章主要介紹了解決JAVA遍歷List集合時(shí),刪除數(shù)據(jù)出現(xiàn)的問題,文中講解非常細(xì)致,幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-07-07Java實(shí)現(xiàn)兩人五子棋游戲(二) 畫出棋盤
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)兩人五子棋游戲,畫出五子棋的棋盤,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03Java超詳細(xì)教你寫一個(gè)斗地主洗牌發(fā)牌系統(tǒng)
這篇文章主要介紹了怎么用Java來你寫一個(gè)斗地主種洗牌和發(fā)牌的功能,斗地主相信大家都知道,同時(shí)也知道每一局都要洗牌打亂順序再發(fā)牌,本篇我們就來實(shí)現(xiàn)這個(gè)功能,感興趣的朋友跟隨文章往下看看吧2022-03-03java的新特性反射機(jī)制應(yīng)用及操作示例詳解
這篇文章主要為大家介紹了java的新特性反射機(jī)制的操作示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05