java如何創(chuàng)建普通二叉樹
java創(chuàng)建二叉樹
這段時間一直在復習數(shù)據(jù)結(jié)構(gòu)的知識。
從最基礎(chǔ)的開始,實現(xiàn)一個普通的二叉樹。但發(fā)現(xiàn)也不那么簡單。因為之前學數(shù)據(jù)結(jié)構(gòu)時是用C語言寫的。
指針用來對結(jié)構(gòu)體的值操作比較好理解。但java沒有指針。
而Node節(jié)點在方法中傳遞的是地址。
如果直接對形參進行new操作是錯誤的。無法改變實參的值的。這一點坑了我很久,然后一頓查資料。
時隔很久,終于填上這個坑了
下面是以遞歸創(chuàng)建的二叉樹.還有一些常見的遍歷和樹的高度與樹的最大寬度.
- 一個方法不能修改一個基本數(shù)據(jù)類型的參數(shù)
- 一個方法可以修改一個對象參數(shù)的狀態(tài)
- 一個方法不能實現(xiàn)讓對象參數(shù)引用一個新對象(這句話在這里尤為適用)
代碼中的二叉樹如下圖
下面是非常簡單的實現(xiàn)
這里為了,后面的輸出格式,使用了JDK的動態(tài)代理。并寫了一個接口
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; /** * 為了方便展示,并沒有將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傳遞進去 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); } // 非遞歸遍歷二叉樹 // 先序遍歷 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; } } } // 層序遍歷 利用隊列 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); } } // 樹高 遞歸,分別求出左子樹的深度、右子樹的深度,兩個深度的較大值+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); } /** * 為什么不直接寫成調(diào)用 root,而是另寫一個方法去調(diào)用呢 因為,這樣可以不再為root,單獨設(shè)置一個臨時變量去存貯 * 而且也固定外部調(diào)用的方法,而不用關(guān)心內(nèi)部的實現(xiàn) */ public void printHeight() { int height = getHeightByRecursion(root); System.out.print(height); } // 利用層序遍歷,得到樹的最大寬度 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); } }
下面是寫的測試類
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; } }
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java 調(diào)用 HTTP 接口的 7 種方式示例代碼(全網(wǎng)最全指南)
在開發(fā)過程中,調(diào)用 HTTP 接口是最常見的需求之一,本文將詳細介紹 Java 中 7 種主流的調(diào)用 HTTP 接口的方式,包括每種工具的優(yōu)缺點和完整代碼實現(xiàn),感興趣的朋友一起看看吧2025-02-02Java使用jni清屏功能的實現(xiàn)(只針對cmd)
JNI是Java Native Interface的縮寫,它提供了若干的API實現(xiàn)了Java和其他語言的通信(主要是C&C++)。這篇文章主要介紹了Java使用jni清屏功能的實現(xiàn)(只針對cmd) ,感興趣的朋友跟隨腳本之家小編一起學習吧2018-05-05詳解Java中IO字節(jié)流基本操作(復制文件)并測試性能
這篇文章主要介紹了Java中IO字節(jié)流基本操作(復制文件)并測試性能,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-04-04Springboot詳解如何實現(xiàn)SQL注入過濾器過程
這篇文章主要介紹了基于springboot實現(xiàn)SQL注入過濾器,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2022-06-06