java如何創(chuàng)建普通二叉樹(shù)
java創(chuàng)建二叉樹(shù)
這段時(shí)間一直在復(fù)習(xí)數(shù)據(jù)結(jié)構(gòu)的知識(shí)。
從最基礎(chǔ)的開(kāi)始,實(shí)現(xiàn)一個(gè)普通的二叉樹(shù)。但發(fā)現(xiàn)也不那么簡(jiǎn)單。因?yàn)橹皩W(xué)數(shù)據(jù)結(jié)構(gòu)時(shí)是用C語(yǔ)言寫(xiě)的。
指針用來(lái)對(duì)結(jié)構(gòu)體的值操作比較好理解。但java沒(méi)有指針。
而Node節(jié)點(diǎn)在方法中傳遞的是地址。
如果直接對(duì)形參進(jìn)行new操作是錯(cuò)誤的。無(wú)法改變實(shí)參的值的。這一點(diǎn)坑了我很久,然后一頓查資料。
時(shí)隔很久,終于填上這個(gè)坑了
下面是以遞歸創(chuàng)建的二叉樹(shù).還有一些常見(jiàn)的遍歷和樹(shù)的高度與樹(shù)的最大寬度.
- 一個(gè)方法不能修改一個(gè)基本數(shù)據(jù)類(lèi)型的參數(shù)
- 一個(gè)方法可以修改一個(gè)對(duì)象參數(shù)的狀態(tài)
- 一個(gè)方法不能實(shí)現(xiàn)讓對(duì)象參數(shù)引用一個(gè)新對(duì)象(這句話(huà)在這里尤為適用)
代碼中的二叉樹(shù)如下圖
下面是非常簡(jiǎn)單的實(shí)現(xiàn)
這里為了,后面的輸出格式,使用了JDK的動(dòng)態(tài)代理。并寫(xiě)了一個(gè)接口
package test.tree; public interface AbstractBinaryTree { void printPostOder(); void printPostOderByRecursion(); void printPreOder(); void printPreOderByRecursion(); void printInOderByRecursion(); void printInOder(); void printHeight(); void printMaxWidth(); void printLevelOrder(); }
主要的代碼
package test.tree; import java.util.LinkedList; import java.util.Queue; import java.util.Stack; /** * 為了方便展示,并沒(méi)有將Node屬性私有 */ class Node { public String data; public Node left = null; public Node right = null; public boolean flag; Node(String data) { this.data = data; } Node() { } @Override public String toString() { return this.data; } } public class BinaryTree implements AbstractBinaryTree{ private Node root = new Node(); public Node getRoot() { return root; } public void printNode(Node node) { if (node.data == null) { System.out.print(""); } else { System.out.print(node.data); } } public BinaryTree(String tree) { String[] treeNodes = tree.split(","); createTreeByRecursion(treeNodes); } private int createTreeByRecursion(Node node, String[] treeNodes, int n) { if ("#".equals(treeNodes[n])) return n + 1; node.data = treeNodes[n]; node.left = new Node(); int left = createTreeByRecursion(node.left, treeNodes, n + 1); node.right = new Node(); int right = createTreeByRecursion(node.right, treeNodes, left); return right; } public void createTreeByRecursion(String[] treeNodes) { createTreeByRecursion(root, treeNodes, 0); } /** * 先序非遞歸創(chuàng)建 */ public void createTree(String[] treeNodes) { Stack<Node> stack = new Stack<>(); int index = 0; Node node = root; while (index < treeNodes.length) { while (true) { if ("#".equals(treeNodes[index])) { node = stack.pop(); if (node.flag == false) { node.left = null; node.flag = true; stack.push(node); } else { node.right = null; } // 記得加1 index++; break; } if (node.flag == true) { node.right = new Node(); node = node.right; } node.data = treeNodes[index]; stack.push(node); node.left = new Node(); node = node.left; index++; } if (node.flag == false) { stack.push(node); node.flag = true; node = node.right; } else { node = stack.peek(); node.flag = true; } } } // 遞歸調(diào)用的方法,需要將root傳遞進(jìn)去 private void printPreOderByRecursion(Node node) { if (node == null) return; printNode(node); printPreOderByRecursion(node.left); printPreOderByRecursion(node.right); } public void printPreOderByRecursion() { printPreOderByRecursion(root); } private void printInOderByRecursion(Node node) { if (node == null) return; printInOderByRecursion(node.left); printNode(node); printInOderByRecursion(node.right); } public void printInOderByRecursion() { printInOderByRecursion(root); } private void printPostOderByRecursion(Node node) { if (node == null) return; printPostOderByRecursion(node.left); printPostOderByRecursion(node.right); printNode(node); } public void printPostOderByRecursion() { printPostOderByRecursion(root); } // 非遞歸遍歷二叉樹(shù) // 先序遍歷 public void printPreOder() { Stack<Node> stack = new Stack<>(); Node tempNode = root; while (true) { while (tempNode != null) { printNode(tempNode); stack.push(tempNode); tempNode = tempNode.left; } if (stack.isEmpty()) { break; } tempNode = stack.pop(); tempNode = tempNode.right; } } // 中序遍歷 public void printInOder() { Stack<Node> stack = new Stack<>(); Node tempNode = root; while (true) { while (tempNode != null) { stack.push(tempNode); tempNode = tempNode.left; } if (stack.isEmpty()) { break; } tempNode = stack.pop(); printNode(tempNode); tempNode = tempNode.right; } } // 后序遍歷 public void printPostOder() { Stack<Node> stack = new Stack<>(); Node tempNode = root; while (true) { while (tempNode != null) { if (tempNode.flag == true) { tempNode = tempNode.right; } else { stack.push(tempNode); tempNode = tempNode.left; } } tempNode = stack.pop(); if (tempNode.flag == false) { stack.push(tempNode); tempNode.flag = true; tempNode = tempNode.right; } else { printNode(tempNode); if (stack.isEmpty()) { break; } tempNode = stack.peek(); tempNode.flag = true; } } } // 層序遍歷 利用隊(duì)列 public void printLevelOrder() { Queue<Node> queue = new LinkedList<>(); Node tempNode = root; queue.offer(tempNode); while (!queue.isEmpty()) { Node topNode = queue.poll(); if (topNode == null) continue; printNode(topNode); queue.offer(topNode.left); queue.offer(topNode.right); } } // 樹(shù)高 遞歸,分別求出左子樹(shù)的深度、右子樹(shù)的深度,兩個(gè)深度的較大值+1 public int getHeightByRecursion(Node node) { if (node == null) { return 0; } int left = getHeightByRecursion(node.left); int right = getHeightByRecursion(node.right); return 1 + Math.max(left, right); } /** * 為什么不直接寫(xiě)成調(diào)用 root,而是另寫(xiě)一個(gè)方法去調(diào)用呢 因?yàn)?這樣可以不再為root,單獨(dú)設(shè)置一個(gè)臨時(shí)變量去存貯 * 而且也固定外部調(diào)用的方法,而不用關(guān)心內(nèi)部的實(shí)現(xiàn) */ public void printHeight() { int height = getHeightByRecursion(root); System.out.print(height); } // 利用層序遍歷,得到樹(shù)的最大寬度 public void printMaxWidth() { Queue<Node> queue = new LinkedList<>(); Queue<Node> queueTemp = new LinkedList<>(); int maxWidth = 1; Node tempNode = root; queue.offer(tempNode); while (!queue.isEmpty()) { while (!queue.isEmpty()) { Node topNode = queue.poll(); if (topNode == null) continue; if (topNode.left.data != null) { queueTemp.offer(topNode.left); } if (topNode.right.data != null) { queueTemp.offer(topNode.right); } } maxWidth = Math.max(maxWidth, queueTemp.size()); queue = queueTemp; queueTemp = new LinkedList<>(); } System.out.print(maxWidth); } }
下面是寫(xiě)的測(cè)試類(lèi)
package test.tree; import java.lang.reflect.Proxy; public class BinaryTreeTest { public static void main(String[] args) { String treeStr = "A,B,D,#,#,#,C,#,E,#,#"; // String treeStr = "A,#,#"; AbstractBinaryTree binaryTree = BinaryTreeTest.proxyBinaryTree(treeStr); binaryTree.printPostOder(); binaryTree.printPostOderByRecursion(); binaryTree.printPreOder(); binaryTree.printPreOderByRecursion(); binaryTree.printInOderByRecursion(); binaryTree.printInOder(); binaryTree.printLevelOrder(); binaryTree.printHeight(); binaryTree.printMaxWidth(); } public static AbstractBinaryTree proxyBinaryTree(String treeStr) { AbstractBinaryTree binaryTree = new BinaryTree(treeStr); Object newProxyInstance = Proxy.newProxyInstance(binaryTree.getClass().getClassLoader(), binaryTree.getClass().getInterfaces(), (proxy, method, args) -> { System.out.println(method.getName()); Object invoke = method.invoke(binaryTree, args); System.out.println(); return invoke; }); return (AbstractBinaryTree) newProxyInstance; } }
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java 生成隨機(jī)單據(jù)號(hào)的實(shí)現(xiàn)示例
本文主要介紹了Java 生成隨機(jī)單據(jù)號(hào)的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-09-09Java 調(diào)用 HTTP 接口的 7 種方式示例代碼(全網(wǎng)最全指南)
在開(kāi)發(fā)過(guò)程中,調(diào)用 HTTP 接口是最常見(jiàn)的需求之一,本文將詳細(xì)介紹 Java 中 7 種主流的調(diào)用 HTTP 接口的方式,包括每種工具的優(yōu)缺點(diǎn)和完整代碼實(shí)現(xiàn),感興趣的朋友一起看看吧2025-02-02Java使用jni清屏功能的實(shí)現(xiàn)(只針對(duì)cmd)
JNI是Java Native Interface的縮寫(xiě),它提供了若干的API實(shí)現(xiàn)了Java和其他語(yǔ)言的通信(主要是C&C++)。這篇文章主要介紹了Java使用jni清屏功能的實(shí)現(xiàn)(只針對(duì)cmd) ,感興趣的朋友跟隨腳本之家小編一起學(xué)習(xí)吧2018-05-05java isPalindrome方法在密碼驗(yàn)證中的應(yīng)用
這篇文章主要為大家介紹了java isPalindrome方法在密碼驗(yàn)證中的簡(jiǎn)單應(yīng)用技巧,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12詳解Java中IO字節(jié)流基本操作(復(fù)制文件)并測(cè)試性能
這篇文章主要介紹了Java中IO字節(jié)流基本操作(復(fù)制文件)并測(cè)試性能,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04關(guān)于java編譯過(guò)程中的bug說(shuō)明
本篇文章是對(duì)java編譯過(guò)程中的bug進(jìn)行了詳細(xì)的說(shuō)明介紹,需要的朋友參考下2013-05-05Java Socket實(shí)現(xiàn)UDP編程淺析
類(lèi) DatagramSocket 何 DatagramPacket(數(shù)據(jù)包/數(shù)據(jù)報(bào)) 實(shí)現(xiàn)了基于 UDP協(xié)議網(wǎng)絡(luò)程序;UDP數(shù)據(jù)報(bào)通過(guò)數(shù)據(jù)報(bào)套接字 DatagramSocket 發(fā)送和接收,系統(tǒng)不保證 UDP數(shù)據(jù)報(bào)一定能夠安全送達(dá)目的地,也不確定什么時(shí)候可以抵達(dá)2022-11-11Springboot詳解如何實(shí)現(xiàn)SQL注入過(guò)濾器過(guò)程
這篇文章主要介紹了基于springboot實(shí)現(xiàn)SQL注入過(guò)濾器,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2022-06-06