二叉樹的相關操作,包括創(chuàng)建,中序、先序、后序(遞歸和非遞歸),其中重點的是java在先序創(chuàng)建二叉樹和后序非遞歸遍歷的的實現(xiàn)。
成都創(chuàng)新互聯(lián)公司專注于企業(yè)全網(wǎng)整合營銷推廣、網(wǎng)站重做改版、西湖網(wǎng)站定制設計、自適應品牌網(wǎng)站建設、H5頁面制作、商城網(wǎng)站建設、集團公司官網(wǎng)建設、外貿(mào)網(wǎng)站建設、高端網(wǎng)站制作、響應式網(wǎng)頁設計等建站業(yè)務,價格優(yōu)惠性價比高,為西湖等各大城市提供網(wǎng)站開發(fā)制作服務。
package com.algorithm.tree;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Queue;
import java.util.Scanner;
import java.util.Stack;
import java.util.concurrent.LinkedBlockingQueue;
public class Tree {
private Node root;
public Tree() {
}
public Tree(Node root) {
this.root = root;
}
//創(chuàng)建二叉樹
public void buildTree() {
Scanner scn = null;
try {
scn = new Scanner(new File("input.txt"));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
root = createTree(root,scn);
}
//先序遍歷創(chuàng)建二叉樹
private Node createTree(Node node,Scanner scn) {
String temp = scn.next();
if (temp.trim().equals("#")) {
return null;
} else {
node = new Node((T)temp);
node.setLeft(createTree(node.getLeft(), scn));
node.setRight(createTree(node.getRight(), scn));
return node;
}
}
//中序遍歷(遞歸)
public void inOrderTraverse() {
inOrderTraverse(root);
}
public void inOrderTraverse(Node node) {
if (node != null) {
inOrderTraverse(node.getLeft());
System.out.println(node.getValue());
inOrderTraverse(node.getRight());
}
}
//中序遍歷(非遞歸)
public void nrInOrderTraverse() {
StackNode stack = new StackNode();
Node node = root;
while (node != null || !stack.isEmpty()) {
while (node != null) {
stack.push(node);
node = node.getLeft();
}
node = stack.pop();
System.out.println(node.getValue());
node = node.getRight();
}
}
//先序遍歷(遞歸)
public void preOrderTraverse() {
preOrderTraverse(root);
}
public void preOrderTraverse(Node node) {
if (node != null) {
System.out.println(node.getValue());
preOrderTraverse(node.getLeft());
preOrderTraverse(node.getRight());
}
}
//先序遍歷(非遞歸)
public void nrPreOrderTraverse() {
StackNode stack = new StackNode();
Node node = root;
while (node != null || !stack.isEmpty()) {
while (node != null) {
System.out.println(node.getValue());
stack.push(node);
node = node.getLeft();
}
node = stack.pop();
node = node.getRight();
}
}
//后序遍歷(遞歸)
public void postOrderTraverse() {
postOrderTraverse(root);
}
public void postOrderTraverse(Node node) {
if (node != null) {
postOrderTraverse(node.getLeft());
postOrderTraverse(node.getRight());
System.out.println(node.getValue());
}
}
//后續(xù)遍歷(非遞歸)
public void nrPostOrderTraverse() {
StackNode stack = new StackNode();
Node node = root;
Node preNode = null;//表示最近一次訪問的節(jié)點
while (node != null || !stack.isEmpty()) {
while (node != null) {
stack.push(node);
node = node.getLeft();
}
node = stack.peek();
if (node.getRight() == null || node.getRight() == preNode) {
System.out.println(node.getValue());
node = stack.pop();
preNode = node;
node = null;
} else {
node = node.getRight();
}
}
}
//按層次遍歷
public void levelTraverse() {
levelTraverse(root);
}
public void levelTraverse(Node node) {
QueueNode queue = new LinkedBlockingQueueNode();
queue.add(node);
while (!queue.isEmpty()) {
Node temp = queue.poll();
if (temp != null) {
System.out.println(temp.getValue());
queue.add(temp.getLeft());
queue.add(temp.getRight());
}
}
}
}
//樹的節(jié)點
class Node {
private Node left;
private Node right;
private T value;
public Node() {
}
public Node(Node left,Node right,T value) {
this.left = left;
this.right = right;
this.value = value;
}
public Node(T value) {
this(null,null,value);
}
public Node getLeft() {
return left;
}
public void setLeft(Node left) {
this.left = left;
}
public Node getRight() {
return right;
}
public void setRight(Node right) {
this.right = right;
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
測試代碼:
package com.algorithm.tree;
public class TreeTest {
/**
* @param args
*/
public static void main(String[] args) {
Tree tree = new Tree();
tree.buildTree();
System.out.println("中序遍歷");
tree.inOrderTraverse();
tree.nrInOrderTraverse();
System.out.println("后續(xù)遍歷");
//tree.nrPostOrderTraverse();
tree.postOrderTraverse();
tree.nrPostOrderTraverse();
System.out.println("先序遍歷");
tree.preOrderTraverse();
tree.nrPreOrderTraverse();
//
}
}
首先我想問為什么要用LinkedList 來建立二叉樹呢? LinkedList 是線性表,
樹是樹形的, 似乎不太合適。
其實也可以用數(shù)組完成,而且效率更高.
關鍵是我覺得你這個輸入本身就是一個二叉樹啊,
String input = "ABCDE F G";
節(jié)點編號從0到8. 層次遍歷的話:
對于節(jié)點i.
leftChild = input.charAt(2*i+1); //做子樹
rightChild = input.charAt(2*i+2);//右子樹
如果你要將帶有節(jié)點信息的樹存到LinkedList里面, 先建立一個節(jié)點類:
class Node{
public char cValue;
public Node leftChild;
public Node rightChild;
public Node(v){
this.cValue = v;
}
}
然后遍歷input,建立各個節(jié)點對象.
LinkedList tree = new LinkedList();
for(int i=0;i input.length;i++)
LinkedList.add(new Node(input.charAt(i)));
然后為各個節(jié)點設置左右子樹:
for(int i=0;iinput.length;i++){
((Node)tree.get(i)).leftChild = (Node)tree.get(2*i+1);
((Node)tree.get(i)).rightChild = (Node)tree.get(2*i+2);
}
這樣LinkedList 就存儲了整個二叉樹. 而第0個元素就是樹根,思路大體是這樣吧。
定義一個結(jié)點類:
public class Node {
private int value;
private Node leftNode;
private Node rightNode;
public Node getRightNode() {
return rightNode;
}
public void setRightNode(Node rightNode) {
this.rightNode = rightNode;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public Node getLeftNode() {
return leftNode;
}
public void setLeftNode(Node leftNode) {
this.leftNode = leftNode;
}
}
初始化結(jié)點樹:
public void initNodeTree()
{
int nodeNumber;
HashMapString, Integer map = new HashMapString, Integer();
Node nodeTree = new Node();
Scanner reader = new Scanner(System.in);
nodeNumber = reader.nextInt();
for(int i = 0; i nodeNumber; i++) {
int value = reader.nextInt();
String str = reader.next();
map.put(str, value);
}
if (map.containsKey("#")) {
int value = map.get("#");
nodeTree.setValue(value);
setChildNode(map, value, nodeTree);
}
preTraversal(nodeTree);
}
private void setChildNode(HashMapString, Integer map, int nodeValue, Node parentNode) {
int value = 0;
if (map.containsKey("L" + nodeValue)) {
value = map.get("L" + nodeValue);
Node leftNode = new Node();
leftNode.setValue(value);
parentNode.setLeftNode(leftNode);
setChildNode(map, value, leftNode);
}
if (map.containsKey("R" + nodeValue)) {
value = map.get("R" + nodeValue);
Node rightNode = new Node();
rightNode.setValue(value);
parentNode.setRightNode(rightNode);
setChildNode(map, value, rightNode);
}
}
前序遍歷該結(jié)點樹:
public void preTraversal(Node nodeTree) {
if (nodeTree != null) {
System.out.print(nodeTree.getValue() + "\t");
preTraversal(nodeTree.getLeftNode());
preTraversal(nodeTree.getRightNode());
}
}
import java.util.ArrayList;
// 樹的一個節(jié)點
class TreeNode {
Object _value = null; // 他的值
TreeNode _parent = null; // 他的父節(jié)點,根節(jié)點沒有PARENT
ArrayList _childList = new ArrayList(); // 他的孩子節(jié)點
public TreeNode( Object value, TreeNode parent ){
this._parent = parent;
this._value = value;
}
public TreeNode getParent(){
return _parent;
}
public String toString() {
return _value.toString();
}
}
public class Tree {
// 給出寬度優(yōu)先遍歷的值數(shù)組,構(gòu)建出一棵多叉樹
// null 值表示一個層次的結(jié)束
// "|" 表示一個層次中一個父親節(jié)點的孩子輸入結(jié)束
// 如:給定下面的值數(shù)組:
// { "root", null, "left", "right", null }
// 則構(gòu)建出一個根節(jié)點,帶有兩個孩子("left","right")的樹
public Tree( Object[] values ){
// 創(chuàng)建根
_root = new TreeNode( values[0], null );
// 創(chuàng)建下面的子節(jié)點
TreeNode currentParent = _root; // 用于待創(chuàng)建節(jié)點的父親
//TreeNode nextParent = null;
int currentChildIndex = 0; // 表示 currentParent 是他的父親的第幾個兒子
//TreeNode lastNode = null; // 最后一個創(chuàng)建出來的TreeNode,用于找到他的父親
for ( int i = 2; i values.length; i++ ){
// 如果null ,表示下一個節(jié)點的父親是當前節(jié)點的父親的第一個孩子節(jié)點
if ( values[i] == null ){
currentParent = (TreeNode)currentParent._childList.get(0);
currentChildIndex = 0;
continue;
}
// 表示一個父節(jié)點的所有孩子輸入完畢
if ( values[i].equals("|") ){
if ( currentChildIndex+1 currentParent._childList.size() ){
currentChildIndex++;
currentParent = (TreeNode)currentParent._parent._childList.get(currentChildIndex);
}
continue;
}
TreeNode child = createChildNode( currentParent, values[i] );
}
}
TreeNode _root = null;
public TreeNode getRoot(){
return _root;
}
/**
// 按寬度優(yōu)先遍歷,打印出parent子樹所有的節(jié)點
private void printSteps( TreeNode parent, int currentDepth ){
for ( int i = 0; i parent._childList.size(); i++ ){
TreeNode child = (TreeNode)parent._childList.get(i);
System.out.println(currentDepth+":"+child);
}
if ( parent._childList.size() != 0 ) System.out.println(""+null);// 為了避免葉子節(jié)點也會打印null
//打印 parent 同層的節(jié)點的孩子
if ( parent._parent != null ){ // 不是root
int i = 1;
while ( i parent._parent._childList.size() ){// parent 的父親還有孩子
TreeNode current = (TreeNode)parent._parent._childList.get(i);
printSteps( current, currentDepth );
i++;
}
}
// 遞歸調(diào)用,打印所有節(jié)點
for ( int i = 0; i parent._childList.size(); i++ ){
TreeNode child = (TreeNode)parent._childList.get(i);
printSteps( child, currentDepth+1 );
}
}
// 按寬度優(yōu)先遍歷,打印出parent子樹所有的節(jié)點
public void printSteps(){
System.out.println(""+_root);
System.out.println(""+null);
printSteps(_root, 1 );
}**/
// 將給定的值做為 parent 的孩子,構(gòu)建節(jié)點
private TreeNode createChildNode( TreeNode parent, Object value ){
TreeNode child = new TreeNode( value , parent );
parent._childList.add( child );
return child;
}
public static void main(String[] args) {
Tree tree = new Tree( new Object[]{ "root", null,
"left", "right", null,
"l1","l2","l3", "|", "r1","r2",null } );
//tree.printSteps();
System.out.println(""+ ( (TreeNode)tree.getRoot()._childList.get(0) )._childList.get(0) );
System.out.println(""+ ( (TreeNode)tree.getRoot()._childList.get(0) )._childList.get(1) );
System.out.println(""+ ( (TreeNode)tree.getRoot()._childList.get(0) )._childList.get(2) );
System.out.println(""+ ( (TreeNode)tree.getRoot()._childList.get(1) )._childList.get(0) );
System.out.println(""+ ( (TreeNode)tree.getRoot()._childList.get(1) )._childList.get(1) );
}
}
java:二叉樹添加和查詢方法
package arrays.myArray;
public class BinaryTree {
private Node root;
// 添加數(shù)據(jù)
public void add(int data) {
// 遞歸調(diào)用
if (null == root)
root = new Node(data, null, null);
else
addTree(root, data);
}
private void addTree(Node rootNode, int data) {
// 添加到左邊
if (rootNode.data data) {
if (rootNode.left == null)
rootNode.left = new Node(data, null, null);
else
addTree(rootNode.left, data);
} else {
// 添加到右邊
if (rootNode.right == null)
rootNode.right = new Node(data, null, null);
else
addTree(rootNode.right, data);
}
}
// 查詢數(shù)據(jù)
public void show() {
showTree(root);
}
private void showTree(Node node) {
if (node.left != null) {
showTree(node.left);
}
System.out.println(node.data);
if (node.right != null) {
showTree(node.right);
}
}
}
class Node {
int data;
Node left;
Node right;
public Node(int data, Node left, Node right) {
this.data = data;
this.left = left;
this.right = right;
}
}
二叉樹具有以下重要性質(zhì):
性質(zhì)1 二叉樹第i層上的結(jié)點數(shù)目最多為2i-1(i≥1)。
證明:用數(shù)學歸納法證明:
歸納基礎:i=1時,有2i-1=20=1。因為第1層上只有一個根結(jié)點,所以命題成立。
歸納假設:假設對所有的j(1≤ji)命題成立,即第j層上至多有2j-1個結(jié)點,證明j=i時命題亦成立。
歸納步驟:根據(jù)歸納假設,第i-1層上至多有2i-2個結(jié)點。由于二叉樹的每個結(jié)點至多有兩個孩子,故第i層上的結(jié)點數(shù)至多是第i-1層上的最大結(jié)點數(shù)的2倍。即j=i時,該層上至多有2×2i-2=2i-1個結(jié)點,故命題成立。
性質(zhì)2 深度為k的二叉樹至多有2k-1個結(jié)點(k≥1)。
證明:在具有相同深度的二叉樹中,僅當每一層都含有最大結(jié)點數(shù)時,其樹中結(jié)點數(shù)最多。因此利用性質(zhì)1可得,深度為k的二叉樹的結(jié)點數(shù)至多為:
20+21+…+2k-1=2k-1
故命題正確。
性質(zhì)3 在任意-棵二叉樹中,若終端結(jié)點的個數(shù)為n0,度為2的結(jié)點數(shù)為n2,則no=n2+1。
證明:因為二叉樹中所有結(jié)點的度數(shù)均不大于2,所以結(jié)點總數(shù)(記為n)應等于0度結(jié)點數(shù)、1度結(jié)點(記為n1)和2度結(jié)點數(shù)之和:
n=no+n1+n2 (式子1)
另一方面,1度結(jié)點有一個孩子,2度結(jié)點有兩個孩子,故二叉樹中孩子結(jié)點總數(shù)是:
nl+2n2
樹中只有根結(jié)點不是任何結(jié)點的孩子,故二叉樹中的結(jié)點總數(shù)又可表示為:
n=n1+2n2+1 (式子2)
由式子1和式子2得到:
no=n2+1
滿二叉樹和完全二叉樹是二叉樹的兩種特殊情形。
1、滿二叉樹(FullBinaryTree)
一棵深度為k且有2k-1個結(jié)點的二又樹稱為滿二叉樹。
滿二叉樹的特點:
(1) 每一層上的結(jié)點數(shù)都達到最大值。即對給定的高度,它是具有最多結(jié)點數(shù)的二叉樹。
(2) 滿二叉樹中不存在度數(shù)為1的結(jié)點,每個分支結(jié)點均有兩棵高度相同的子樹,且樹葉都在最下一層上。
圖(a)是一個深度為4的滿二叉樹。
2、完全二叉樹(Complete BinaryTree)
若一棵二叉樹至多只有最下面的兩層上結(jié)點的度數(shù)可以小于2,并且最下一層上的結(jié)點都集中在該層最左邊的若干位置上,則此二叉樹稱為完全二叉樹。
特點:
(1) 滿二叉樹是完全二叉樹,完全二叉樹不一定是滿二叉樹。
(2) 在滿二叉樹的最下一層上,從最右邊開始連續(xù)刪去若干結(jié)點后得到的二叉樹仍然是一棵完全二叉樹。
(3) 在完全二叉樹中,若某個結(jié)點沒有左孩子,則它一定沒有右孩子,即該結(jié)點必是葉結(jié)點。
如圖(c)中,結(jié)點F沒有左孩子而有右孩子L,故它不是一棵完全二叉樹。
圖(b)是一棵完全二叉樹。
性質(zhì)4 具有n個結(jié)點的完全二叉樹的深度為
證明:設所求完全二叉樹的深度為k。由完全二叉樹定義可得:
深度為k得完全二叉樹的前k-1層是深度為k-1的滿二叉樹,一共有2k-1-1個結(jié)點。
由于完全二叉樹深度為k,故第k層上還有若干個結(jié)點,因此該完全二叉樹的結(jié)點個數(shù):
n2k-1-1。
另一方面,由性質(zhì)2可得:
n≤2k-1,
即:2k-1-ln≤2k-1
由此可推出:2k-1≤n2k,取對數(shù)后有:
k-1≤lgnk
又因k-1和k是相鄰的兩個整數(shù),故有
,
由此即得:
注意:
的證明