Redis研究-3.4 爲什麼使用Redis跳躍表

好幾天沒把筆記整理上來了,一個是這幾天在忙着一些投標以及項目論文的事情,哈哈,還有麼 就是畫圖也是比較耗費我時間的,若是有好的畫圖建議或者工具,麻煩推薦一下,謝謝。廢話很少說,直接進入今天的兩個主題:二叉搜索樹,平衡二叉樹。 java

 

1.二叉搜索樹(BST) node

二叉搜索樹的定義很簡單:是二叉樹,且知足兩個條件:若是有左孩子,則左孩子的關鍵字必定不大於父節點的關鍵字,若是有右孩子,則右孩子的關鍵字不小於父節點的關鍵字。同時,左右子樹都是二叉搜索樹。 工具

 

                                                    BST_1 學習

中序遍歷獲得的結果是:一、二、三、四、五、六、七、八、九、10 this

                                                   BST_2 code

中序遍歷獲得的結果是:一、二、三、四、五、六、七、八、九、10 遞歸

 

如今有一個場景,加入我要在這顆樹中查找一個關鍵字11,若是沒有的話,則加入到這顆樹中,查詢步驟是: rem

1.針對BST_1,根節點是6,由於11大於6,則查找根節點的右孩子(由於二叉搜索樹的右孩子的關鍵字不小於父節點); get

2.右孩子的值是9,小於11,繼續查他的右孩子; it

3.右孩子的值是10,小於11,繼續查他的右孩子;

4.由於沒有右孩子了,因此,須要將其添加爲右孩子。

針對BST_2,咱們只須要一直找右孩子就能夠了。咱們再看一個二叉搜索樹:

                                         BST3

中序遍歷獲得的結果是:一、二、三、四、五、六、七、九、10

如今我要查找一個節點,其中的關鍵字是8的一個節點,若是不在這顆樹中,則把它加到樹中做爲一個節點:

1.根節點是6,小於8,找右孩子;

2.右孩子的值是9大於8,找他的左孩子;

3.左孩子的值7小於8,找他的右孩子;

4.由於沒有右孩子了,因此,將其添加爲7的右孩子。

 

從上面幾個過程當中咱們發現一個規律:動態查找過程當中,咱們不須要重構這個結構,只是在葉子節點上進行操做,很是方便。

那若是要刪除一個節點呢?

刪除節點的時候,有幾種狀況須要考慮:

1.該節點是葉子節點,所以,不用重構;

2.該節點只有左子樹或者右子樹,則把左子樹或者右子樹的根,接到刪除節點的父節點上就能夠了;

3.若是該節點二者都有呢?

 

咱們一個一個的來看:

1.該節點是葉子節點。

咱們要刪除BST3中的節點7,則先按照查詢步驟找到這個節點,發現他沒有左子樹,也沒有右子樹,則直接刪除,並把該節點的父節點的左孩子或者右孩子(取決於該節點是左孩子仍是右孩子)清空便可。

2.該節點只有左子樹。

咱們要刪除BST3中的節點4,則先按照查詢步驟找到這個節點,發現他只有左子樹,所以,只要刪除該節點,並把該節點的左孩子放在改節點的位置便可。

3.該節點只有右子樹:

咱們要刪除BST2中的節點5,則先按照查詢步驟找到這個節點,發現他只有由子樹,所以,只要刪除該節點,並把該節點的右孩子放在該節點的位置便可。

 

4.該節點有左子樹,也有右子樹。

咱們如今要刪除BST1中的根節點,則中序遍歷這個節點的左子樹,獲得的此節點前的那個節點,就是要刪除節點的前驅。

好比上述根節點的左子樹的中序遍歷是:一、二、三、5,則,我是要刪除節點6的前驅,將該前驅替代要刪除的節點的位置,並設置左指向和右指向便可。

,咱們如今再來看一BST。

如今我要刪除節點9,按照上面的步驟,9有左右孩子,所以,先作9的左子樹的中序遍歷,找到9的前驅是8.5,而後來替換。最終獲得結果是:

 

,說了那麼多,仍是上上代碼吧,此次用java代碼:

package com.tang.bst;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class BST<Key extends Comparable<Key>> {
	BSTNode<Key> root;

	public BST() {
	}

	/**
	 * 插入一個節點
	 * 
	 * @param data
	 *            節點的數據
	 * @return
	 */
	public boolean insert(Key data) {
		if (null == data)
			return false;
		if (null == this.root) {
			this.root = new BSTNode<Key>(data);
			this.root.parent = null;
			this.root.leftChild = null;
			this.root.rightChild = null;
			return true;
		} else {
			return insertBST(this.root, data);
		}

	}

	private boolean insertBST(BSTNode<Key> node, Key data) {
		// 左分支,右分支的判斷
		int lOrR = node.data.compareTo(data);
		if (lOrR == 0) {
			return false;
		} else if (lOrR < 0) {
			// 右子樹
			if (null == node.rightChild) {
				BSTNode<Key> rChild = new BSTNode<Key>(data);
				rChild.parent = node;
				node.rightChild = rChild;
				return true;
			} else {
				return insertBST(node.rightChild, data);
			}
		} else {
			// 左子樹
			if (null == node.leftChild) {
				BSTNode<Key> lChild = new BSTNode<Key>(data);
				lChild.parent = node;
				node.leftChild = lChild;
				return true;
			} else {
				return insertBST(node.leftChild, data);
			}
		}
	}

	/**
	 * 在這棵樹中,指定一個節點,而後開始非遞歸方式中序遍歷以這個節點爲根節點的二叉樹
	 * 
	 * @param node
	 *            指定爲根節點的節點
	 * @return
	 */
	public List<BSTNode<Key>> noRecurseInOrderTraverse(Key data) {
		if (null == this.root)
			return null;
		BSTNode<Key> beginRoot = null;
		if (null == data) {
			beginRoot = this.root;// 若是沒有指定節點爲根節點,那麼就從這棵樹的根節點開始
		} else {
			BSTNode<Key> sNode = searchBST(this.root, data);
			beginRoot = sNode;
		}
		List<BSTNode<Key>> stack = new ArrayList<BSTNode<Key>>();
		List<BSTNode<Key>> retStack = new ArrayList<BSTNode<Key>>();
		if (null != beginRoot) {
			stack.add(beginRoot);
		}

		while (!stack.isEmpty()) {
			while (beginRoot != null && null != beginRoot.leftChild) {
				beginRoot = beginRoot.leftChild;
				stack.add(beginRoot);
			}
			if (!stack.isEmpty()) {
				BSTNode<Key> tmpNode = stack.get(stack.size() - 1);
				stack.remove(stack.size() - 1);
				retStack.add(tmpNode);
				if (tmpNode != null && null != tmpNode.rightChild) {
					beginRoot = tmpNode.rightChild;
					stack.add(beginRoot);
				}
			}
		}
		return retStack;
	}

	/**
	 * 查找指定的節點,若是沒有,則將他加入到這顆樹上
	 * 
	 * @param data
	 * @return 0:表示在原樹上就有,1:表示添加進去的新節點,-1:表示查詢中出錯
	 */
	public boolean search(Key data) {
		if (null == data) {
			return false;
		}
		if (null == this.root) {
			return false;
		}
		return searchBST(this.root, data) == null ? false : true;
	}

	private BSTNode<Key> searchBST(BSTNode<Key> searhNode, Key data) {
		if (null == data) {
			return null;
		}
		if (null == searhNode) {
			return null;
		}
		int lOrR = searhNode.data.compareTo(data);
		if (lOrR > 0) {
			// 要往左子樹去找
			return searchBST(searhNode.leftChild, data);
		} else if (lOrR == 0) {
			// 已經找到了,直接返回去
			return searhNode;
		} else {
			// 要往右子樹去找
			return searchBST(searhNode.rightChild, data);
		}

	}

	/**
	 * 查找指定的節點,若是沒有的話,插入節點
	 * 
	 * @param data
	 * @return
	 */
	public boolean searchOrInsert(Key data) {
		return search(data) == false ? insert(data) : true;
	}

	/**
	 * 刪除指定的節點
	 * 
	 * @param data
	 * @return
	 */
	public boolean delete(Key data) {
		if (null == this.root || null == data) {
			return false;
		}
		BSTNode<Key> node = searchBST(this.root, data);
		if (null == node) {
			return false;
		}
		BSTNode<Key> parent = node.parent;
		BSTNode<Key> leftChild = node.leftChild;
		if (null == node.rightChild) {
			// 由於沒有右孩子,所以,只要從新接上她的左孩子就能夠了
			if (null == parent) {
				// 說明他是根節點
				if (null != leftChild) {
					node.leftChild.parent = null;
				} else {
					this.root = null;
				}
			} else {
				node.parent.leftChild = leftChild;
			}
		} else if (null == node.leftChild) {
			// 由於沒有左孩子,只要從新接上她的右孩子就能夠了
			if (parent == null) {
				// 說明他就是根節點
				if (null != node.rightChild) {
					node.rightChild.parent = null;
				} else {
					this.root = null;
				}
			} else {
				node.parent.rightChild = node.rightChild;
			}
		} else {
			// 既有左子樹,又有右子樹
			// 中序遍歷此節點的左子樹,找到此節點的前驅
			// 此前驅的特色是,要麼是葉子節點,要麼是隻有左節點
			System.out.println(node.rightChild==null);
			List<BSTNode<Key>> stack=noRecurseInOrderTraverse(node.leftChild.data);
			BSTNode<Key> preNode=stack.get(stack.size()-1);
			BSTNode<Key> rightNode=node.rightChild;
			node.data=preNode.data;
			if(preNode.leftChild!=null){
				node.leftChild=preNode.leftChild;
			}
			if(preNode.parent!=null){
				if(preNode.parent.leftChild.data.compareTo(preNode.data)==0){
					preNode.parent.leftChild=null;
				}else{
					preNode.parent.rightChild=null;//這裏有問題
				}
			}
			node.rightChild=rightNode;
			System.out.println(node.rightChild==null);
		}

		return true;
	}

	public static void main(String[] args) {
		BST<Integer> bst = new BST<Integer>();
		bst.insert(new Integer(6));
		bst.insert(new Integer(5));
		bst.insert(new Integer(9));
		bst.insert(new Integer(2));
		bst.insert(new Integer(8));
		bst.insert(new Integer(10));
		bst.insert(new Integer(1));
		bst.insert(new Integer(4));
		bst.insert(new Integer(3));
		List<BSTNode<Integer>> stack = bst.noRecurseInOrderTraverse(null);
		for (Iterator<BSTNode<Integer>> iterator = stack.iterator(); iterator
				.hasNext();) {
			BSTNode<Integer> bstNode = (BSTNode<Integer>) iterator.next();
			System.out.print(bstNode.data + "---");
		}

		bst.delete(new Integer(5));

		System.out.println("刪除以後");
		stack = bst.noRecurseInOrderTraverse(null);
		for (Iterator<BSTNode<Integer>> iterator = stack.iterator(); iterator
				.hasNext();) {
			BSTNode<Integer> bstNode = (BSTNode<Integer>) iterator.next();
			System.out.print(bstNode.data + "---");
		}
	}

}

經過上面的學習,咱們能夠看到,二叉搜索樹受輸入順序影響很大,有可能就是造成了一個線性表,效率很是低。咋整呢?收看下一節,歡迎加qq:359311095討論

相關文章
相關標籤/搜索