據結構與算法(九) 二叉搜索樹的刪除操做

一、二叉搜索樹的刪除操做

介紹

關於二叉搜索樹的刪除操做,先弄清如何找到前驅節點和後繼節點java

前驅節點(predecessor)

介紹

  • 前驅節點:中序遍歷時的前一個節點node

  • 若是左子樹存在,從該節點的左子節點的最右的節點。spa

  • 若是左子樹 == null && 父節點!= null 父節點爲父節點遍歷,一直到節點關係發生改變。以下圖所示。3d

  • 若是左子樹 == null && 父節點== null ,沒有前驅節點。code

代碼

public Node<E> findPredecessorNode(E element) {
  return findPredecessorNode(node(element));
}

private Node<E> findPredecessorNode(Node<E> element) {
  if (element.left != null) {
    Node<E> node = element.left;
    while (node.right!= null) {
      node = node.right;
    }
    return node;
  }

  while (element.parent != null && element == element.parent.left) {
    element = element.parent;
  }
  return element.parent;
}
複製代碼

後繼節點(succeessor)

  • 前驅節點:中序遍歷時的後一個節點
  • 若是右子樹存在,從該節點的左子節點的最左的節點。
  • 若是右子樹 == null && 父節點!= null 父節點爲父節點遍歷,一直到節點關係發生改變。
  • 若是右子樹 == null && 父節點== null ,沒有後繼節點。

刪除節點

葉子節點

  • 直接刪除

度爲1的節點

  • 用子節點替換既可

度爲2的節點

  • 找到前驅或者後繼節點的值,並替換原節點。
  • 他的前驅、後繼節點的度只多是0或者是1。
private void remove(Node<E> node) {
  if (node == null) return;
  size--;

  // 度爲2的節點
  if (node.twoChildren()) { 
    // 找到後繼節點
    Node<E> s = findSucceessorNode(node);
    // 用後繼節點的值覆蓋原節點的值
    node.element = s.element;

    node = s;
  }

  // 刪除的node節點 (node的度必然是1或者0) 若是是0 replacement爲null
  Node<E> replacement = node.left != null ? node.left : node.right;

  // 度爲1
  if (replacement != null) {
    // 更改parent
    replacement.parent = node.parent;
    // 更改parent的 chil
    if (node.parent == null) { // node是度爲1的節點而且是根節點
      root = replacement;
    } else if (node == node.parent.left) {
      node.parent.left = replacement;
    } else { // node == node.parent.right
      node.parent.right = replacement;
    }
  } else if (node.parent == null) { // node是葉子節點而且是根節點
    root = null;
  } else { // node是葉子節點
    if (node == node.parent.left) {
      node.parent.left = null;
    } else { 
      node.parent.right = null;
    }
  }
}
複製代碼

二、根據遍歷結果重構二叉樹

  • 中序遍歷+ 前/後序遍歷
    • 能夠肯定一顆惟一二叉樹
  • 前序遍歷+ 後序遍歷
    • 若是他是一顆真二叉樹(Proper Binary Tree) ,結果是惟一的。
    • 其餘狀況 不惟一。
List<Integer> perorder = Arrays.asList(5,1,2,4,3,9);
List<Integer> inorder = Arrays.asList(2,1,4,5,9,3);


private Node<E> RefactoringTree(List<E> perorderList, List<E> inorderList) {
  if (perorderList.size() == 0|| inorderList.size() == 0) {
    return null;
  }
  E element = perorderList.get(0);

  Node<E> root = new Node<>(element, null);
  perorderList = perorderList.subList(1, perorderList.size());
  int index = inorderList.indexOf(element);
  List<E> leftInorderList = inorderList.subList(0, index);
  List<E> rightInorderList = inorderList.subList(index + 1, inorderList.size());

  List<E> leftperOrderList = perorderList.subList(0, leftInorderList.size());
  List<E> rightperOrderList = perorderList.subList(leftperOrderList.size(), perorderList.size());

  root.left = RefactoringTree(leftperOrderList, leftInorderList);
  root.right = RefactoringTree(rightperOrderList, rightInorderList);
  return  root;
}
複製代碼

喜歡的能夠關注下個人公衆號,會在第一時間更新cdn

相關文章
相關標籤/搜索