- 最近學習的有點累。導致二叉樹學習的有點模糊
- 我們之前學過數組 和鏈表 數組插入比較慢 鏈表查詢比較慢。這時候我們就需要使用樹這種結構。都比較快
- 樹的基本概念
- 根:樹最上面的節點稱爲根節點,一棵樹只有一個根節點
- 父節點:每一個節點都有一條邊向上連接到另一個節點,這個節點就是稱爲下面這個節點的父節點
- 子節點:每一個節點都有條向下連接的節點,下面的這個節點就是該節點的子節點
- 葉子節點:沒有子節點的節點也叫葉子節點.
- 子樹:每一個節點都可以作爲一個子樹的根。他和他的所有子節點組合在一起就是個子樹
- 查找節點:從根節點開始查找,如果查找的節點值比當前節點的值小,則繼續查找左子樹,否則查找右子樹
- 遍歷樹:遍歷樹是根據一個特定的順序訪問樹的每一個節點,根據順序的不同分爲前序,中序,後序遍歷三種。
前序遍歷。
- (1)訪問根節點
- (2)前序遍歷左子樹
- (3)前序遍歷右子樹
中序遍歷。
- (1)中序遍歷左子樹
- (2)訪問根節點
- (3)中序遍歷右子樹
後序遍歷。
- (1)後序遍歷左子樹
- (2)後序遍歷右子樹
- (3)訪問根節點
上代碼:
/**
* 二叉樹的節點類
* @author Administrator
*
*/
public class Node {
public int iData;
public String sData;
public Node leftChild;
public Node rightChild;
public Node(int iData,String sData) {
this.iData = iData;
this.sData =sData;
}
public Node() {
// TODO Auto-generated constructor stub
}
public void dispalyNode(){
System.out.print("{"+ iData +"}");
}
}
二叉樹的具體實現
package com.chapter5_1;
public class Tree {
//根節點
public Node root;
/**
* 二叉樹的插入 s
*/
public void insert(int d,String s){
//新節點
Node newNode = new Node(d,s);
//引用當前的節點
Node current = root;
//引用父節點
Node parent;
if(current == null){
root = newNode;
return ;//如果root節點爲空的話,直接點添加都結束了
}
while(true){
//先將當前的節點付給一個parent. 這個節點一直在變動
parent = current;
if(d < current.iData){
//當前的節點變成剛纔的左節點
current = current.leftChild;
if(current == null){
parent.leftChild =newNode;
return;
}
}else{//d >
// 變成剛纔的又節點
current = current.rightChild;
if(current == null){
parent.rightChild= newNode;
return;
}
}
}
}
/**
* 查找二叉樹
* @param value
* @return
*/
public Node find(int value){
Node current = root;
while(current.iData !=value){
//如果這個值比當前的節點值小,那麼找左子節點
if(current.iData > value){
current = current.leftChild;
}else{
current = current.rightChild;
}
if(current == null){
return null;
}
}
return current;
}
public void traverse(int traverseType){
switch (traverseType) {
case 1://
//前序遍歷
System.out.println("前序遍歷");
frontOrder(root);
break;
case 2:
System.out.println("中序遍歷");
inOrder(root);
break;
case 3:
System.out.println("後序遍歷");
postOrder(root);
break;
default:
break;
}
System.out.println("--------------------------------");
}
/**
* 前序遍歷
* @param localNode
*/
public void frontOrder(Node localNode){
if(localNode != null){
//訪問根節點
System.out.println(localNode.iData +","+localNode.sData);
//前序遍歷左子樹
frontOrder(localNode.leftChild);
//前序遍歷右子樹
frontOrder(localNode.rightChild);
}
}
/**
* 中序遍歷 -
* 1.中序遍歷左子樹
* 2.訪問根節點
* 3.中序遍歷右子樹(從小到大)
* @param localNode
*/
public void inOrder(Node localNode){
if(localNode != null){
//中序遍歷左子樹
inOrder(localNode.leftChild);
//訪問根節點
System.out.println(localNode.iData +","+localNode.sData);
//中序遍歷右子樹
inOrder(localNode.rightChild);
}
}
/**
* 後序遍歷。。先遍歷左子樹-右子樹-訪問根節點
* @param localNode
*/
public void postOrder(Node localNode){
if(localNode != null){
//後序遍歷左子樹
postOrder(localNode.leftChild);
//後序遍歷右子樹
postOrder(localNode.rightChild);
//訪問根節點
System.out.println(localNode.iData +","+localNode.sData);
}
}
/**
* 刪除一個節點
* 有3種情況
* 1.該節點是葉子節點
* 2.該節點只有 一個節點
* 3.該節點有倆個節點。需要找到右邊節點的最小節點。(中序遍歷後繼。。找到)
* @param value
* @return
*/
public boolean delete(int value){
//引用當前節點
Node current = root;
//引用父節點
Node parent = root;
//判斷是否爲左子節點
boolean isLeftChild =true;
while(current.iData != value){
//先賦值
parent = current;
//如果這個值比當前的節點值小,那麼找左子節點
if(current.iData > value){
current = current.leftChild;
isLeftChild =true;
}else{
current = current.rightChild;
isLeftChild =false;
}
if(current == null){
return false;
}
}
//刪除葉子節點,也就是該節點沒有子節點
if(current.leftChild == null && current.rightChild == null){
if(current == root){//刪除的是根。並且根麼有子子節點
root = null;
}else if(isLeftChild){//刪除的葉子節點是父節點的左子節點
parent.leftChild = null;
}else{
parent.rightChild = null;
}
}else if(current.rightChild == null){//只有一個節點 意思就是左子節點有數據
if(current == root){//如果是根的話。就是根節點=當前的左子節點
root = current.leftChild;
}else if(isLeftChild){
parent.leftChild = current.leftChild;
}else{
parent.rightChild = current.leftChild;
}
}else if(current.leftChild == null){//只有一個節點 意思就是右子節點有數據
if(current == root) root = current.rightChild;
//這裏看起來比較繞。。所以刪除的時候可以自己畫一個圖。自己想
else if(isLeftChild){
parent.leftChild = current.rightChild;
}else{
parent.rightChild = current.rightChild;
}
}else{//有倆個節點。。。。
Node successor = getSuccessor(current);
if(current ==root){
root = successor;
}else if(isLeftChild){
parent.leftChild = successor;
}else{
parent.rightChild = successor;
}
successor.leftChild =current.leftChild;
}
return true;
}
public Node getSuccessor(Node delNode){
Node successor = delNode;
Node successorParent = delNode;
Node current =delNode.rightChild;
while(current != null){
successorParent =successor;
successor =current;//先右邊然後然後一直找左子節點
current = current.leftChild;//一直往左子節點找
}
if(successor != delNode.rightChild){//這裏沒有看懂。
successorParent.leftChild = successor.rightChild;
successor.rightChild = delNode.rightChild;
}
return successor;
}
}
測試代碼:
package com.chapter5_1;
public class Test {
public static void main(String[] args) {
Tree t = new Tree();
t.insert(10,"thinkpad");
t.insert(20,"mac");
t.insert(15,"del");
t.insert(3,"leishen");
t.insert(40,"zhangsan");
t.insert(16,"liao");
t.insert(4,"luyao");
// System.out.println(t.root.rightChild.iData);
// System.out.println(t.root.rightChild.leftChild.iData);
// System.out.println(t.root.leftChild.iData);
// Node node = t.find(15);
//// System.out.println(node.iData +", " + node.sData);
// node = t.find(3);
//// System.out.println(node.iData +", " + node.sData);
t.delete(3);
// t.traverse(1);
t.traverse(2);
// t.traverse(3);
t.delete(16);
// t.traverse(1);
t.traverse(2);
}
}
至於測試結果我就不貼了。很多。在刪除二叉樹有倆個節點的時。我沒有弄明白。我先貼代碼。最近比較累。