資料結構(七)——樹結構(Tree) 之二叉樹的常用操作
阿新 • • 發佈:2019-01-08
一.鏈式儲存的二叉樹的操作
1.遍歷二叉樹
- 先序遍歷:根-->左-->右
- 中序遍歷:左-->根-->右
- 後序遍歷:左-->右-->根
2.二叉樹結點的查詢
結點的查詢也可以分為先序查詢,中序查詢和後序查詢。方式和遍歷方式相似。
3.刪除二叉樹結點
- 二叉樹抽象類程式碼
package cn.kimtian.tree; /** * 鏈式儲存的二叉樹 * * @author kimtian */ public class BinaryTree { /** * 根結點 */ TreeNode root; /** * 設定根結點 * * @param root 根結點 */ public void setRoot(TreeNode root) { this.root = root; } /** * 獲取根結點 * * @return TreeNode 根結點 */ public TreeNode getRoot() { return root; } /** * 先序遍歷 */ public void frontShow() { if (root != null) { root.frontShow(); } } /** * 中序遍歷 */ public void middleShow() { if (root != null) { root.middleShow(); } } /** * 後序遍歷 */ public void behindShow() { if (root != null) { root.behindShow(); } } /** * 查詢二叉樹的結點--先序查詢 * * @param i 查詢的結點的值 */ public TreeNode frontSearch(int i) { return root.frontSearch(i); } /** * 查詢二叉樹的結點--中序查詢 * * @param i 查詢的結點的值 */ public TreeNode middleSearch(int i) { return root.middleSearch(i); } /** * 查詢二叉樹的結點--後序查詢 * * @param i 查詢的結點的值 */ public TreeNode behindSearch(int i) { return root.behindSearch(i); } /** * 刪除二叉樹的結點/子樹 * * @param i 查詢的結點的值 */ public void deleteTreeNode(int i) { if (root.value == i) { root = null; } else { root.deleteTreeNode(i); } } }
- 二叉樹的結點
package cn.kimtian.tree; /** * 樹裡面的結點 * * @author kimtian */ public class TreeNode { /** * 樹裡面的值,結點的權 */ int value; /** * 左兒子 */ TreeNode leftNode; /** * 右兒子 */ TreeNode rightNode; public TreeNode(int value) { this.value = value; } public void setLeftNode(TreeNode leftNode) { this.leftNode = leftNode; } public void setRightNode(TreeNode rightNode) { this.rightNode = rightNode; } /** * 先序遍歷--遞迴思想 */ public void frontShow() { //先遍歷當前結點的內容 System.out.print(value + " "); //左結點 if (leftNode != null) { leftNode.frontShow(); } //右結點 if (rightNode != null) { rightNode.frontShow(); } } /** * 中序遍歷 */ public void middleShow() { //左結點 if (leftNode != null) { leftNode.middleShow(); } System.out.print(value + " "); //右結點 if (rightNode != null) { rightNode.middleShow(); } } /** * 後序遍歷 */ public void behindShow() { //左結點 if (leftNode != null) { leftNode.behindShow(); } //右結點 if (rightNode != null) { rightNode.behindShow(); } System.out.print(value + " "); } /** * 先序查詢 * * @param i 查詢的結點的值 */ public TreeNode frontSearch(int i) { TreeNode target = null; //對比當前結點的值 if (value == i) { return this; } //當前結點的值不是要查詢的結點 else { //查詢左兒子 if (leftNode != null) { target = leftNode.frontSearch(i); } if (target != null) { return target; } //查詢右兒子 if (rightNode != null) { target = rightNode.frontSearch(i); } if (target != null) { return target; } } return target; } /** * 中序查詢 * * @param i 查詢的結點的值 */ public TreeNode middleSearch(int i) { TreeNode target = null; //對比左兒子的值 if (leftNode != null) { target = leftNode.middleSearch(i); } if (target != null) { return target; } //對比當前結點的值 if (value == i) { return this; } //查詢右兒子 if (rightNode != null) { target = rightNode.middleSearch(i); } if (target != null) { return target; } return target; } /** * 後序查詢 * * @param i 查詢的結點的值 */ public TreeNode behindSearch(int i) { TreeNode target = null; //對比左兒子的值 if (leftNode != null) { target = leftNode.behindSearch(i); } if (target != null) { return target; } //查詢右兒子 if (rightNode != null) { target = rightNode.behindSearch(i); } if (target != null) { return target; } //對比當前結點的值 if (value == i) { return this; } return target; } /** * 刪除二叉樹的結點/子樹 * * @param i 要刪除的結點的值 */ public void deleteTreeNode(int i) { TreeNode parent = this; //判斷左兒子 if (parent.leftNode != null && parent.leftNode.value == i) { parent.leftNode = null; return; } //判斷右邊兒子 if (parent.rightNode != null && parent.rightNode.value == i) { parent.rightNode = null; return; } //遞迴檢查並刪除左兒子 parent = leftNode; if (parent != null) { parent.deleteTreeNode(i); } //遞迴檢查並刪除右兒子 parent = rightNode; if (parent != null) { parent.deleteTreeNode(i); } } }
(3)測試類。
package cn.kimtian.tree; /** * 測試鏈式儲存的二叉樹 * * @author kimtian */ public class TestBinaryTree { public static void main(String[] args) { //建立一棵樹 BinaryTree binaryTree = new BinaryTree(); //建立一個根結點 TreeNode root = new TreeNode(1); //將根結點賦給樹 binaryTree.setRoot(root); //建立一個子左結點 TreeNode leftTwo = new TreeNode(2); //建立一個子右結點 TreeNode rightTwo = new TreeNode(3); //給根的左結點賦值 root.setLeftNode(leftTwo); //給根的右結點賦值 root.setRightNode(rightTwo); //第三層結點 TreeNode llThree = new TreeNode(4); TreeNode lrThree = new TreeNode(5); TreeNode rlThree = new TreeNode(6); TreeNode rrThree = new TreeNode(7); leftTwo.setLeftNode(llThree); leftTwo.setRightNode(lrThree); rightTwo.setLeftNode(rlThree); rightTwo.setRightNode(rrThree); //先序遍歷 binaryTree.frontShow(); System.out.println(); //中序遍歷 binaryTree.middleShow(); System.out.println(); //後序遍歷 binaryTree.behindShow(); System.out.println(); System.out.println("===================="); //先序查詢 TreeNode result = binaryTree.frontSearch(5); System.out.println(result); System.out.println(result == lrThree); TreeNode result1 = binaryTree.frontSearch(10); System.out.println(result1); System.out.println(); System.out.println("===================="); //中序查詢 TreeNode result2 = binaryTree.middleSearch(5); System.out.println(result2); System.out.println(result2 == lrThree); TreeNode result3 = binaryTree.middleSearch(10); System.out.println(result3); System.out.println(); System.out.println("===================="); //後序查詢 TreeNode result4 = binaryTree.behindSearch(5); System.out.println(result4); System.out.println(result4 == lrThree); TreeNode result5 = binaryTree.behindSearch(10); System.out.println(result5); //先序遍歷 binaryTree.frontShow(); System.out.println(); //刪除一個子樹 binaryTree.deleteTreeNode(1); //先序遍歷 binaryTree.frontShow(); System.out.println(); } }
二.順序儲存的二叉樹的操作
順序儲存的二叉樹通常情況只考慮完全二叉樹。
- 第n個元素的左子結點是2*n+1
- 第n個元素的右子結點是2*n+2
- 第n個元素的父結點是(n-1)/2
1.遍歷二叉樹
- 先序遍歷:根-->左-->右
- 中序遍歷:左-->根-->右
- 後序遍歷:左-->右-->根
package cn.kimtian.tree.arraybinarytree;
/**
* 順序儲存的二叉樹
*
* @author kimtian
*/
public class ArrayBinaryTree {
/**
* 一個儲存樹的陣列
*/
int[] data;
public ArrayBinaryTree(int[] data) {
this.data = data;
}
/**
* 前序遍歷
*
* @param index 從哪個結點開始遍歷
*/
public void frontShow(int index) {
if (data == null || data.length == 0) {
return;
}
//先遍歷當前結點的內容
System.out.print(data[index] + " ");
//處理左子結點
if (2 * index + 1 < data.length) {
frontShow(2 * index + 1);
}
//處理右子結點
if (2 * index + 2 < data.length) {
frontShow(2 * index + 2);
}
}
/**
* 前序遍歷 過載方法
*/
public void frontShow() {
frontShow(0);
}
/**
* 中序遍歷
*
* @param index 從哪個結點開始遍歷
*/
public void middleShow(int index) {
if (data == null || data.length == 0) {
return;
}
//處理左子結點
if (2 * index + 1 < data.length) {
middleShow(2 * index + 1);
}
//先遍歷當前結點的內容
System.out.print(data[index] + " ");
//處理右子結點
if (2 * index + 2 < data.length) {
middleShow(2 * index + 2);
}
}
/**
* 中序遍歷
*/
public void middleShow() {
middleShow(0);
}
/**
* 後序遍歷
*
* @param index 從哪個結點開始遍歷
*/
public void behindShow(int index) {
if (data == null || data.length == 0) {
return;
}
//處理左子結點
if (2 * index + 1 < data.length) {
behindShow(2 * index + 1);
}
//處理右子結點
if (2 * index + 2 < data.length) {
behindShow(2 * index + 2);
}
//先遍歷當前結點的內容
System.out.print(data[index] + " ");
}
/**
* 後序遍歷
*/
public void behindShow() {
behindShow(0);
}
}