1. 程式人生 > >數據結構實現(四)二叉查找樹java實現

數據結構實現(四)二叉查找樹java實現

.com ML treenode 設置 AC getparent 邏輯圖 技術分享 ldb

轉載 http://www.cnblogs.com/CherishFX/p/4625382.html

二叉查找樹的定義:

  二叉查找樹或者是一顆空樹,或者是一顆具有以下特性的非空二叉樹:

    1. 若左子樹非空,則左子樹上所有節點關鍵字值均小於根節點的關鍵字;

    2. 若右子樹非空,則右子樹上所有節點關鍵字值均大於根節點的關鍵字;

    3. 左、右子樹本身也分別是一顆二叉查找樹。

二叉查找樹的實現,功能有:

  1. 用一個數組去構建二叉查找樹

  2. 二叉查找樹的中序遍歷和層次遍歷

  3. 插入節點

  4. 查找節點

5. 查找二叉樹中的最大值和最小值

  6. 得到節點的直接父節點

  7. 得到節點的直接前驅和直接後繼節點

  8. 刪除節點

package dataStructures;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
import java.util.Stack;

public class BinarySearchTree {
    private TreeNode<Integer> root = null; // 根節點

    public BinarySearchTree() {
    }

    // 用一個數組去構建二叉查找樹
public TreeNode<Integer> buildBST(Integer[] array) { if (array.length == 0) { return null; } else { root = null; // 初始化樹為空樹 for (int i = 0; i < array.length; i++) { // 依次將每個元素插入 root = insertNode(root, array[i]); }
return root; } } // 在二叉查找樹中插入一個數據域為data的結點,新插入的結點一定是某個葉子節點 private TreeNode<Integer> insertNode(TreeNode<Integer> node, Integer data) { if (node == null) { // 原樹為空,新插入的記錄為根節點 node = new TreeNode<Integer>(data, null, null); } else { if (node.data != data) { // 樹中不存在相同關鍵字的結點 if (node.data > data) { // 根節點>插入數據,插入到左子樹中 node.lchild = insertNode(node.lchild, data); } else { // 根節點<插入數據,插入到右子樹中 node.rchild = insertNode(node.rchild, data); } } } return node; } // 二叉查找樹的中序遍歷,可以得到一個遞增的有序數列 public void inOrder(TreeNode<Integer> node) { if (node != null) { inOrder(node.lchild); System.out.print(node.data + " "); inOrder(node.rchild); } } // 二叉查找樹的層次遍歷 public void levelOrder(TreeNode<Integer> root) { Queue<TreeNode<Integer>> nodeQueue = new LinkedList<TreeNode<Integer>>(); TreeNode<Integer> node = null; nodeQueue.add(root); // 將根節點入隊 while (!nodeQueue.isEmpty()) { // 隊列不空循環 node = nodeQueue.peek(); System.out.print(node.data + " "); nodeQueue.poll(); // 隊頭元素出隊 if (node.lchild != null) { // 左子樹不空,則左子樹入隊列 nodeQueue.add(node.lchild); } if (node.rchild != null) { // 右子樹不空,則右子樹入隊列 nodeQueue.add(node.rchild); } } } // 查找數據域為data的結點,若不存在,返回null public TreeNode<Integer> searchNode(TreeNode<Integer> node, Integer data) { while (node != null && node.data != data) { if (node.data > data) { node = node.lchild; // 根節點>數據,向左走 } else { node = node.rchild; // 根節點<數據,向右走 } } return node; } // 查找最大值:不斷地尋找右子節點 public TreeNode<Integer> getMaxData(TreeNode<Integer> node) { if (node.rchild == null) { return node; } else { return getMaxData(node.rchild); } } // 查找最小值:不斷地尋找左子節點 public TreeNode<Integer> getMinData(TreeNode<Integer> node) { if (node.lchild == null) { return node; } else { return getMinData(node.lchild); } } // 得到數據域為data的結點的直接父節點parentNode public TreeNode<Integer> getParentNode(TreeNode<Integer> root, Integer data) { TreeNode<Integer> parentNode = root; if (parentNode.data == data) { // 根節點的父節點返回為null return null; } while (parentNode != null) { // 查找當前節點的父節點的左右子節點,若是相等,則返回該父節點 if ((parentNode.lchild != null && parentNode.lchild.data == data) || (parentNode.rchild != null && parentNode.rchild.data == data)) { return parentNode; } else { if (parentNode.data > data) { // 向左查找父節點 parentNode = parentNode.lchild; } else { parentNode = parentNode.rchild; // 向右查找父節點 } } } return null; } /** * 得到結點node的直接前趨 a.該節點左子樹不為空:其前驅節點為其左子樹的最大元素 * b.該節點左子樹為空:其前驅節點為其祖先節點(遞歸),且該祖先節點的右孩子也為其祖先節點 (就是一直往其parent找,出現左拐後的那個祖先節點) */ public TreeNode<Integer> getPrecessor(TreeNode<Integer> root, TreeNode<Integer> node) { if (node == null) { return null; } // a.該節點左子樹不為空:其前驅節點為其左子樹的最大元素 if (node.lchild != null) { return getMaxData(node.lchild); } else { // b.該節點左子樹為空: 其前驅節點為其祖先節點(遞歸) TreeNode<Integer> parentNode = getParentNode(root, node.data); while (parentNode != null && node == parentNode.lchild) { node = parentNode; parentNode = getParentNode(root, parentNode.data); } return parentNode; } } /** * 得到結點node的直接後繼(後繼節點就是比要刪除的節點的關鍵值要大的節點集合中的最小值) a.該節點右子樹不為空,其後繼節點為其右子樹的最小元素 * b.該節點右子樹為空,則其後繼節點為其祖先節點(遞歸),且此祖先節點的左孩子也是該節點的祖先節點, * 就是說一直往上找其祖先節點,直到出現右拐後的那個祖先節點: */ public TreeNode<Integer> getSuccessor(TreeNode<Integer> root, TreeNode<Integer> node) { if (node == null) { return null; } // a.該節點右子樹不為空,其後繼節點為其右子樹的最小元素 if (node.rchild != null) { return getMinData(node.rchild); } else { // b.該節點右子樹為空,則其後繼節點為其最高祖先節點(遞歸) TreeNode<Integer> parentNode = getParentNode(root, node.data); while (parentNode != null && node == parentNode.rchild) { node = parentNode; parentNode = getParentNode(root, parentNode.data); } return parentNode; } } /** * 刪除數據域為data的結點 按三種情況處理: a.如果被刪除結點z是葉子節點,則直接刪除,不會破壞二叉查找樹的性質 * b.如果節點z只有一顆左子樹或右子樹,則讓z的子樹成為z父節點的子樹,代替z的位置 * c.若結點z有左、右兩顆子樹,則令z的直接後繼(或直接前驅)替代z, * 然後從二叉查找樹中刪去這個直接後繼(或直接前驅),這樣就轉換為第一或第二種情況 * * @param node * 二叉查找樹的根節點 * @param data * 需要刪除的結點的數據域 * @return */ public boolean deleteNode(TreeNode<Integer> node, Integer data) { if (node == null) { // 樹為空 throw new RuntimeException("樹為空!"); } TreeNode<Integer> delNode = searchNode(node, data); // 搜索需要刪除的結點 TreeNode<Integer> parent = null; if (delNode == null) { // 如果樹中不存在要刪除的關鍵字 throw new RuntimeException("樹中不存在要刪除的關鍵字!"); } else { parent = getParentNode(node, data); // 得到刪除節點的直接父節點 // a.如果被刪除結點z是葉子節點,則直接刪除,不會破壞二叉查找樹的性質 if (delNode.lchild == null && delNode.rchild == null) { if (delNode == parent.lchild) { // 被刪除節點為其父節點的左孩子 parent.lchild = null; } else { // 被刪除節點為其父節點的右孩子 parent.rchild = null; } return true; } // b1.如果節點z只有一顆左子樹,則讓z的子樹成為z父節點的子樹,代替z的位置 if (delNode.lchild != null && delNode.rchild == null) { if (delNode == parent.lchild) { // 被刪除節點為其父節點的左孩子 parent.lchild = delNode.lchild; } else { // 被刪除節點為其父節點的右孩子 parent.rchild = delNode.lchild; } delNode.lchild = null; // 設置被刪除結點的左孩子為null return true; } // b2.如果節點z只有一顆右子樹,則讓z的子樹成為z父節點的子樹,代替z的位置 if (delNode.lchild == null && delNode.rchild != null) { if (delNode == parent.lchild) { // 被刪除節點為其父節點的左孩子 parent.lchild = delNode.rchild; } else { // 被刪除節點為其父節點的右孩子 parent.rchild = delNode.rchild; } delNode.rchild = null; // 設置被刪除結點的右孩子為null return true; } // c.若結點z有左、右兩顆子樹,則刪除該結點的後繼結點,並用該後繼結點取代該結點 if (delNode.lchild != null && delNode.rchild != null) { TreeNode<Integer> successorNode = getSuccessor(node, delNode); // 得到被刪除結點的後繼節點 deleteNode(node, successorNode.data); // 刪除該結點的後繼結點 delNode.data = successorNode.data; // 用該後繼結點取代該結點 return true; } } return false; } /** * 某些方法的非遞歸實現 1. 插入節點insertNode(): 2. 二叉查找樹的中序遍歷: 3. 得到二叉查找樹的最大值和最小值: */ // 1. 在二叉查找樹中插入一個數據域為data的結點,新插入的結點一定是某個葉子節點 public TreeNode<Integer> insertNode2(TreeNode<Integer> node, Integer data) { TreeNode<Integer> newNode = new TreeNode<Integer>(data, null, null); TreeNode<Integer> tmpNode = node; // 遍歷節點 TreeNode<Integer> pnode = null; // 記錄當前節點的父節點 if (node == null) { // 原樹為空,新插入的記錄為根節點 node = newNode; return node; } while (tmpNode != null) { pnode = tmpNode; if (tmpNode.data == data) { // 樹中存在相同關鍵字的結點,什麽也不做 return node; } else { if (tmpNode.data > data) { // 根節點>插入數據,插入到左子樹中 tmpNode = tmpNode.lchild; } else { // 根節點<插入數據,插入到右子樹中 tmpNode = tmpNode.rchild; } } } if (pnode.data > data) { pnode.lchild = newNode; } else { pnode.rchild = newNode; } return node; } // 2. 二叉查找樹的中序遍歷LNR,可以得到一個遞增的有序數列 public void inOrder2(TreeNode<Integer> node) { Stack<TreeNode<Integer>> nodeStack = new Stack<TreeNode<Integer>>(); TreeNode<Integer> tempNode = node; // 遍歷指針 while (tempNode != null || !nodeStack.isEmpty()) { if (tempNode != null) { nodeStack.push(tempNode); tempNode = tempNode.lchild; } else { tempNode = nodeStack.pop(); System.out.print(tempNode.data + " "); tempNode = tempNode.rchild; } } } // 3.1 查找最大值:不斷地尋找右子節點 public TreeNode<Integer> getMaxData2(TreeNode<Integer> node) { TreeNode<Integer> tempNode = node; while (tempNode.rchild != null) { tempNode = tempNode.rchild; } return tempNode; } // 3.2 查找最小值:不斷地尋找左子節點 public TreeNode<Integer> getMinData2(TreeNode<Integer> node) { TreeNode<Integer> tempNode = node; while (tempNode.lchild != null) { tempNode = tempNode.lchild; } return tempNode; } public static void main(String[] args) { Integer[] array = { 8, 3, 10, 1, 6, 14, 4, 7, 13 }; BinarySearchTree bst = new BinarySearchTree(); TreeNode<Integer> root = bst.buildBST(array); System.out.print("層次遍歷:"); bst.levelOrder(root); System.out.print("\n" + "中序遍歷:"); bst.inOrder(root); System.out.println(); System.out.print("得到最大值:"); System.out.println(bst.getMaxData(root).data); System.out.print("得到最小值:"); System.out.println(bst.getMinData(root).data); System.out.print("向二叉查找樹中插入一個節點,請輸入需插入節點的數據域:"); Scanner input = new Scanner(System.in); int data = input.nextInt(); System.out.print("插入節點" + data + "後,中序遍歷的結果:"); root = bst.insertNode(root, data); bst.inOrder(root); System.out.println("\n" + "在二叉查找樹中查找元素," + "請輸入需要查找的結點值:"); data = input.nextInt(); if (bst.searchNode(root, data) == null) { System.out.println("false"); } else { System.out.println("true"); } System.out.println("查找節點的直接父節點," + "請輸入需要查找的結點值:"); data = input.nextInt(); System.out.print("節點" + data + "的父節點是:"); if (bst.getParentNode(root, data) == null) { System.out.println("null"); } else { System.out.println(bst.getParentNode(root, data).data); } System.out.println("刪除結點," + "請輸入需要刪除的結點值:"); data = input.nextInt(); if (bst.deleteNode(root, data)) { System.out.print("刪除結點後的層次遍歷:"); bst.levelOrder(root); System.out.print("\n" + "刪除結點後的中序遍歷:"); bst.inOrder(root); } } }

邏輯圖

技術分享圖片

技術分享圖片

數據結構實現(四)二叉查找樹java實現