成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

紅黑樹(shù)的刪除

Forelax / 509人閱讀

摘要:紅黑樹(shù)的刪除可能出現(xiàn)的情形討論刪除紅黑樹(shù)中一個(gè)結(jié)點(diǎn),刪除的結(jié)點(diǎn)是其子結(jié)點(diǎn)狀態(tài)和顏色的組合。組合被刪結(jié)點(diǎn)無(wú)子結(jié)點(diǎn),且被刪結(jié)點(diǎn)為紅色此時(shí)直接將結(jié)點(diǎn)刪除即可,不破壞任何紅黑樹(shù)的性質(zhì)。

紅黑樹(shù)的刪除 可能出現(xiàn)的情形討論

刪除紅黑樹(shù)中一個(gè)結(jié)點(diǎn),刪除的結(jié)點(diǎn)是其子結(jié)點(diǎn)狀態(tài)和顏色的組合。子結(jié)點(diǎn)的狀態(tài)有三種:無(wú)子結(jié)點(diǎn)、只有一個(gè)子結(jié)點(diǎn)、有兩個(gè)子結(jié)點(diǎn)。顏色有紅色和黑色兩種。所以共會(huì)有6種組合。

組合1:被刪結(jié)點(diǎn)無(wú)子結(jié)點(diǎn),且被刪結(jié)點(diǎn)為紅色

此時(shí)直接將結(jié)點(diǎn)刪除即可,不破壞任何紅黑樹(shù)的性質(zhì)。

組合2:被刪結(jié)點(diǎn)無(wú)子結(jié)點(diǎn),且被刪結(jié)點(diǎn)為黑色

處理方法略微復(fù)雜,稍后再議。

組合3:被刪結(jié)點(diǎn)有一個(gè)子結(jié)點(diǎn),且被刪結(jié)點(diǎn)為紅色

這種組合是不存在的,如圖假如被刪結(jié)點(diǎn)node只有一個(gè)有值的子結(jié)點(diǎn)value,而以value為根結(jié)點(diǎn)的子樹(shù)中,必然還存在null結(jié)點(diǎn),如此不符合紅黑樹(shù)的性質(zhì)5,對(duì)每個(gè)結(jié)點(diǎn),從該結(jié)點(diǎn)到其所有后代葉結(jié)點(diǎn)的簡(jiǎn)單路徑上,均包含相同數(shù)目的黑色結(jié)點(diǎn)。

組合4:被刪結(jié)點(diǎn)有一個(gè)子結(jié)點(diǎn),且被刪結(jié)點(diǎn)為黑色

這種組合下,被刪結(jié)點(diǎn)node的另一個(gè)子結(jié)點(diǎn)value必然為紅色,此時(shí)直接將node刪掉,用value代替node的位置,并將value著黑即可。

組合5&6:被刪結(jié)點(diǎn)有兩個(gè)子結(jié)點(diǎn),且被刪結(jié)點(diǎn)為黑色或紅色

當(dāng)被刪結(jié)點(diǎn)node有兩個(gè)子結(jié)點(diǎn)時(shí),先要找到這個(gè)被刪結(jié)點(diǎn)的后繼結(jié)點(diǎn)successor,然后用successor代替node的位置,同時(shí)著成node的顏色,此時(shí)相當(dāng)于successor被刪。

因?yàn)閚ode有兩個(gè)子結(jié)點(diǎn),所以successor必然在node的右子樹(shù)中,必然是下圖兩種形態(tài)中的一種。

若是(a)的情形,用successor代替node后,相當(dāng)于successor被刪,若successor為紅色,則變成了組合1;若successor為黑色,則變成了組合2。

若是(b)的情形,用successor代替node后,相當(dāng)于successor被刪,若successor為紅色,則變成了組合1;若successor為黑色,則變成了組合2或4。

綜上

若被刪結(jié)點(diǎn)是組合1或組合4的狀態(tài),很容易處理;被刪結(jié)點(diǎn)不可能是組合3的狀態(tài);被刪結(jié)點(diǎn)是組合5&6的狀態(tài),將變成組合1或組合2或組合4。

再議組合2:被刪結(jié)點(diǎn)無(wú)子結(jié)點(diǎn),且被刪結(jié)點(diǎn)為黑色

因?yàn)閯h除黑色結(jié)點(diǎn)會(huì)破壞紅黑樹(shù)的性質(zhì)5,所以為了不破壞性質(zhì)5,在替代結(jié)點(diǎn)上額外增加一個(gè)黑色,這樣不違背性質(zhì)5而只違背性質(zhì)1,每個(gè)結(jié)點(diǎn)或是黑色或是紅色。此時(shí)將額外的黑色移除,則完成刪除操作。

然后再結(jié)合node原來(lái)的父結(jié)點(diǎn)father和其兄弟結(jié)點(diǎn)brother來(lái)分析。

情形一

brother為黑色,且brother有一個(gè)與其方向一致的紅色子結(jié)點(diǎn)son,所謂方向一致,是指brother為father的左子結(jié)點(diǎn),son也為brother的左子結(jié)點(diǎn);或者brother為father的右子結(jié)點(diǎn),son也為brother的右子結(jié)點(diǎn)。

圖(c)中,白色代表隨便是黑或是紅,方形結(jié)點(diǎn)除了存儲(chǔ)自身黑色外,還額外存儲(chǔ)一個(gè)黑色。將brother和father旋轉(zhuǎn),并重新上色后,變成了圖(d),方形結(jié)點(diǎn)額外存儲(chǔ)的黑色轉(zhuǎn)移到了father,且不違背任何紅黑樹(shù)的性質(zhì),刪除操作完成。

圖(c)中的情形顛倒過(guò)來(lái),也是一樣的操作。

情形二

brother為黑色,且brother有一個(gè)與其方向不一致的紅色子結(jié)點(diǎn)son

圖(e)中,將son和brother旋轉(zhuǎn),重新上色后,變成了圖(f),情形一。

圖(e)中的情形顛倒過(guò)來(lái),也是一樣的操作。

情形三

brother為黑色,且brother無(wú)紅色子結(jié)點(diǎn)

此時(shí)若father為紅,則重新著色即可,刪除操作完成。如圖下圖(g)和(h)。

此時(shí)若father為黑,則重新著色,將額外的黑色存到father,將father作為新的結(jié)點(diǎn)進(jìn)行情形判斷,遇到情形一、情形二,則進(jìn)行相應(yīng)的調(diào)整,完成刪除操作;如果沒(méi)有,則結(jié)點(diǎn)一直上移,直到根結(jié)點(diǎn)存儲(chǔ)額外的黑色,此時(shí)將該額外的黑色移除,即完成了刪除操作。

情形四

brother為紅色,則father必為黑色。

圖(i)中,將brother和father旋轉(zhuǎn),重新上色后,變成了圖(j),新的brother變成了黑色,這樣就成了情形一、二、三中的一種。如果將son和brother旋轉(zhuǎn),無(wú)論怎么重新上色,都會(huì)破壞紅黑樹(shù)的性質(zhì)4或5,例如圖(k)。
圖(i)中的情形顛倒過(guò)來(lái),也是一樣的操作。

代碼
// 結(jié)點(diǎn)
function Node(value) {
  this.value = value
  this.color = "red" // 結(jié)點(diǎn)的顏色默認(rèn)為紅色
  this.parent = null
  this.left = null
  this.right = null
}

function RedBlackTree() {
  this.root = null
}

RedBlackTree.prototype.insert = function (node) {
  // 以二叉搜索樹(shù)的方式插入結(jié)點(diǎn)
  // 如果根結(jié)點(diǎn)不存在,則結(jié)點(diǎn)作為根結(jié)點(diǎn)
  // 如果結(jié)點(diǎn)的值小于node,且結(jié)點(diǎn)的右子結(jié)點(diǎn)不存在,跳出循環(huán)
  // 如果結(jié)點(diǎn)的值大于等于node,且結(jié)點(diǎn)的左子結(jié)點(diǎn)不存在,跳出循環(huán)
  if (!this.root) {
    this.root = node
  } else {
    let current = this.root
    while (current[node.value <= current.value ? "left" : "right"]) {
      current = current[node.value <= current.value ? "left" : "right"]
    }
    current[node.value <= current.value ? "left" : "right"] = node
    node.parent = current
  }
  // 判斷情形
  this._fixTree(node)
  return this
}

RedBlackTree.prototype._fixTree = function (node) {
  // 當(dāng)node.parent不存在時(shí),即為情形1,跳出循環(huán)
  // 當(dāng)node.parent.color === "black"時(shí),即為情形2,跳出循環(huán)
  while (node.parent && node.parent.color !== "black") {
    // 情形3
    let father = node.parent
    let grand = father.parent
    let uncle = grand[grand.left === father ? "right" : "left"]
    if (!uncle || uncle.color === "black") {
      // 葉結(jié)點(diǎn)也是黑色的
      // 情形3.1
      let directionFromFatherToNode = father.left === node ? "left" : "right"
      let directionFromGrandToFather = grand.left === father ? "left" : "right"
      if (directionFromFatherToNode === directionFromGrandToFather) {
        // 具體情形一或二
        // 旋轉(zhuǎn)
        this._rotate(father)
        // 變色
        father.color = "black"
        grand.color = "red"
      } else {
        // 具體情形三或四
        // 旋轉(zhuǎn)
        this._rotate(node)
        this._rotate(node)
        // 變色
        node.color = "black"
        grand.color = "red"
      }
      break // 完成插入,跳出循環(huán)
    } else {
      // 情形3.2
      // 變色
      grand.color = "red"
      father.color = "black"
      uncle.color = "black"
      // 將grand設(shè)為新的node
      node = grand
    }
  }

  if (!node.parent) {
    // 如果是情形1
    node.color = "black"
    this.root = node
  }
}

RedBlackTree.prototype._rotate = function (node) {
  // 旋轉(zhuǎn) node 和 node.parent
  let y = node.parent
  if (y.right === node) {
    if (y.parent) {
      y.parent[y.parent.left === y ? "left" : "right"] = node
    }
    node.parent = y.parent
    if (node.left) {
      node.left.parent = y
    }
    y.right = node.left
    node.left = y
    y.parent = node
  } else {
    if (y.parent) {
      y.parent[y.parent.left === y ? "left" : "right"] = node
    }
    node.parent = y.parent
    if (node.right) {
      node.right.parent = y
    }
    y.left = node.right
    node.right = y
    y.parent = node
  }
}

RedBlackTree.prototype.remove = function (node) {
  while (true) {
    let {
      left,
      right,
      parent,
      color
    } = node
    // 組合1
    if (!left && !right && color === "red") {
      parent[parent.left === node ? "left" : "right"] = null
      return this
    }
    // 組合2
    if (!left && !right && color === "black") {
      if (parent) {
        let nullNode = new Node(null)
        nullNode.parent = parent
        nullNode.color = ["black", "black"]
        parent[parent.left === node ? "left" : "right"] = nullNode
        this._repairTree(nullNode)
      } else {
        this.root = null
      }
      return this
    }
    // 組合4
    if ((!left && right && color === "black") || (left && !right && color === "black")) {
      if (parent) {
        parent[parent.left === node ? "left" : "right"] = node.left || node.right
      } else {
        this.root = node.left || node.right
      }
      node[node.left ? "left" : "right"].color = "black"
      return this
    }
    // 組合5&6
    if (left && right) {
      // 尋找后繼結(jié)點(diǎn)
      let successor = right
      while (successor.left) {
        successor = successor.left
      }
      // 用后繼結(jié)點(diǎn)代替node
      node.value = successor.value
      // 刪除后街結(jié)點(diǎn)
      node = successor
      /* let successorColor = successor.color
      let successorLeft = successor.left
      let successorRight = successor.right
      let successorParent = successor.parent
      // 用后繼節(jié)點(diǎn)代替node
      if (parent) {
        parent[parent.left === node ? "left" : "right"] = successor
      } else {
        this.root = successor
      }
      successor.parent = parent
      successor.left = left
      successor.right = right
      left.parent = successor
      right.parent = successor
      successor.color = color
      // 刪除successor
      node.left = successorLeft
      node.right = successorRight
      node.parent = successorParent
      node.color = successorColor */
    }
  }
}

RedBlackTree.prototype._repairTree = function (node) {
  while (node.parent) {
    let father = node.parent
    let brother = father[father.left === node ? "right" : "left"]
    let son = brother[father.left === node ? "right" : "left"]
    let daugh = brother[father.left === node ? "left" : "right"]
    if (brother.color === "black") {
      if (son && son.color === "red") {
        // 情形一
        // 旋轉(zhuǎn)brother和father
        this._rotate(brother)
        // 變色
        brother.color = father.color
        father.color = "black"
        son.color = "black"
        // 移除black
        if (!node.value) {
          // nullNode
          father[father.left === node ? "left" : "right"] = null
        } else {
          node.color = "black"
        }
        // 刪除操作完成
        return
      } else if (daugh && daugh.color === "red") {
        // 情形二
        // 旋轉(zhuǎn)son和brother
        this._rotate(son)
        // 變色
        son.color = "black"
        brother.color = "red"
        // 變成情形一,繼續(xù)循環(huán)
      } else {
        // 情形三
        // brother無(wú)紅子結(jié)點(diǎn)
        if (father.color === "red") {
          // father為紅色
          father.color = "black"
          brother.color = "red"
          // 移除black
          if (!node.value) {
            // nullNode
            father[father.left === node ? "left" : "right"] = null
          } else {
            node.color = "black"
          }
          // 刪除操作完成
          return
        } else {
          // father為黑色
          father.color = ["black", "black"]
          brother.color = "red"
          // 移除black
          if (!node.value) {
            // nullNode
            father[father.left === node ? "left" : "right"] = null
          } else {
            node.color = "black"
          }
          node = father
          // 結(jié)點(diǎn)上移,繼續(xù)循環(huán)
        }
      }
    } else {
      // 情形四
      this._rotate(brother)
      brother.color = "black"
      father.color = "red"
      // 繼續(xù)循環(huán)
    }
  }
  this.root = node
  node.color = "black"
}

RedBlackTree.prototype.find = function (value) {
  let current = this.root
  while (current.value !== value) {
    current = current[value >= current.value ? "right" : "left"]
  }
  return current
}

let arr = [11, 2, 14, 1, 7, 15, 5, 8, 4]
let tree = new RedBlackTree()
arr.forEach(i => tree.insert(new Node(i)))
let findNode = tree.find(15)
tree.remove(findNode)
debugger

紅黑樹(shù)的插入

一點(diǎn)感悟

紅黑樹(shù)的插入和刪除都是通過(guò)分類討論來(lái)解決的,耐心的分析即可。
為數(shù)不多使用技巧的地方,是為了維持紅黑樹(shù)的性質(zhì),在結(jié)點(diǎn)上存兩個(gè)黑色,當(dāng)然這是算法導(dǎo)論告訴我的。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/89936.html

相關(guān)文章

  • 數(shù)據(jù)結(jié)構(gòu)與算法(十四)深入理解黑樹(shù)和JDK TreeMap和TreeSet源碼分析

    摘要:很多文章或書籍在介紹紅黑樹(shù)的時(shí)候直接上來(lái)就是紅黑樹(shù)的個(gè)基本性質(zhì)插入刪除操作等。這也不奇怪,算法的作者就是紅黑樹(shù)的作者之一。所以,理解樹(shù)對(duì)掌握紅黑樹(shù)是至關(guān)重要的。 本文主要包括以下內(nèi)容: 什么是2-3樹(shù) 2-3樹(shù)的插入操作 紅黑樹(shù)與2-3樹(shù)的等價(jià)關(guān)系 《算法4》和《算法導(dǎo)論》上關(guān)于紅黑樹(shù)的差異 紅黑樹(shù)的5條基本性質(zhì)的分析 紅黑樹(shù)與2-3-4樹(shù)的等價(jià)關(guān)系 紅黑樹(shù)的插入、刪除操作 JDK ...

    curlyCheng 評(píng)論0 收藏0
  • 樹(shù) - (二叉查找樹(shù),黑樹(shù),B樹(shù))- 黑樹(shù)

    摘要:需要執(zhí)行的操作依次是首先,將紅黑樹(shù)當(dāng)作一顆二叉查找樹(shù),將該節(jié)點(diǎn)從二叉查找樹(shù)中刪除然后,通過(guò)旋轉(zhuǎn)和重新著色等一系列來(lái)修正該樹(shù),使之重新成為一棵紅黑樹(shù)。 雖是讀書筆記,但是如轉(zhuǎn)載請(qǐng)注明出處 http://segmentfault.com/blog/exploring/ .. 拒絕伸手復(fù)制黨 關(guān)于二叉樹(shù)的基本知識(shí),可以參見(jiàn):Java 實(shí)現(xiàn)基本數(shù)據(jù)結(jié)構(gòu) 2(樹(shù)) 以下是算法導(dǎo)論第13章的學(xué)...

    yangrd 評(píng)論0 收藏0
  • JDK源碼那些事兒之黑樹(shù)基礎(chǔ)下篇

    摘要:強(qiáng)調(diào)一下,紅黑樹(shù)中的葉子節(jié)點(diǎn)指的都是節(jié)點(diǎn)。故刪除之后紅黑樹(shù)平衡不用調(diào)整。將達(dá)到紅黑樹(shù)平衡。到此關(guān)于紅黑樹(shù)的基礎(chǔ)已經(jīng)介紹完畢,下一章我將就源碼中的進(jìn)行講解說(shuō)明,看一看紅黑樹(shù)是如何在源碼中實(shí)現(xiàn)的。 說(shuō)到HashMap,就一定要說(shuō)到紅黑樹(shù),紅黑樹(shù)作為一種自平衡二叉查找樹(shù),是一種用途較廣的數(shù)據(jù)結(jié)構(gòu),在jdk1.8中使用紅黑樹(shù)提升HashMap的性能,今天就來(lái)說(shuō)一說(shuō)紅黑樹(shù),上一講已經(jīng)給出插入平衡...

    羅志環(huán) 評(píng)論0 收藏0
  • JDK源碼那些事兒之黑樹(shù)基礎(chǔ)上篇

    摘要:用這種范例表示紅黑樹(shù)是可能的,但是這會(huì)改變一些性質(zhì)并使算法復(fù)雜。插入會(huì)出現(xiàn)種情況為根節(jié)點(diǎn),即紅黑樹(shù)的根節(jié)點(diǎn)。 說(shuō)到HashMap,就一定要說(shuō)到紅黑樹(shù),紅黑樹(shù)作為一種自平衡二叉查找樹(shù),是一種用途較廣的數(shù)據(jù)結(jié)構(gòu),在jdk1.8中使用紅黑樹(shù)提升HashMap的性能,今天就來(lái)說(shuō)一說(shuō)紅黑樹(shù)。 前言 限于篇幅,本文只對(duì)紅黑樹(shù)的基礎(chǔ)進(jìn)行說(shuō)明,暫不涉及源碼部分,大部分摘抄自維基百科,這里也貼出對(duì)應(yīng)鏈接...

    qylost 評(píng)論0 收藏0
  • 集合框架知識(shí)系列06 HashMap和TreeMap中的黑樹(shù)

    摘要:在上一節(jié)中,在中用了鏈表和紅黑樹(shù)兩種方式解決沖突,在中也是用紅黑樹(shù)存儲(chǔ)的。其中節(jié)點(diǎn)顏色為黑色紅黑樹(shù)的左旋和右旋紅黑樹(shù)的插入和刪除,都有可能破壞其特性,就不是一棵紅黑樹(shù)了,所以要調(diào)整。 在上一節(jié)中,HashMap在jdk 1.8中用了鏈表和紅黑樹(shù)兩種方式解決沖突,在TreeMap中也是用紅黑樹(shù)存儲(chǔ)的。下面分析一下紅黑樹(shù)的結(jié)構(gòu)和基本操作。 一、紅黑樹(shù)的特征和基本操作 上一節(jié)中已經(jīng)描述了紅黑...

    李增田 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

Forelax

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<