Golang紅黑樹

紅黑樹

紅黑樹是每個節(jié)點都帶有顏色屬性(紅色或黑色)的二叉查找樹伍派。紅黑樹也屬于自平衡二叉查找樹。

紅黑樹具有如下性質(zhì):

1. 每個節(jié)點要么是紅色要么是黑色。

2. 樹的根結(jié)點為黑色節(jié)點。

3. 所有葉子節(jié)點都是黑色節(jié)點(葉子是NIL節(jié)點)赡茸。

4. 每個紅色節(jié)點必須有兩個黑色的子節(jié)點(從每個葉子到根的所有路徑上不能有兩個連續(xù)的紅色節(jié)點)。

5. 從任意節(jié)點到其每個葉子節(jié)點的所有簡單路徑都包含相同數(shù)目的黑色節(jié)點祝闻。

一個紅黑樹的例子:

紅黑樹與平衡二叉樹(AVL)的區(qū)別

  1. 二者雖然都是自平衡二叉樹,但是各自對平衡的定義不同联喘。AVL的平衡是指樹中任意節(jié)點的左右子樹的高度差不超過1华蜒,而在紅黑樹中的平衡則是由上面5點性質(zhì)帶來的: 紅黑樹中的最短子樹h和最高子樹H滿足關(guān)系:H <= 2h。

  2. AVL的平衡只需要通過樹的旋轉(zhuǎn)即可達成平衡豁遭,而紅黑樹除了旋轉(zhuǎn)還需要重繪節(jié)點的顏色叭喜。

  3. AVL中的葉子節(jié)點帶有數(shù)據(jù),而紅黑樹的葉子節(jié)點則是數(shù)據(jù)域為空的黑色節(jié)點蓖谢,即紅黑樹的所有葉子節(jié)點均為黑色捂蕴。

紅黑樹的查找操作與普通二叉樹相同,但是對于插入和刪除操作闪幽,因為新增或者刪除一個節(jié)點可能會打破紅黑樹的性質(zhì)啥辨,所以需要通過旋轉(zhuǎn)和節(jié)點顏色變更來恢復(fù)紅黑樹的性質(zhì)。紅黑樹的一切操作都是圍繞紅黑樹的5點性質(zhì)進行的盯腌。

紅黑樹插入節(jié)點

因為本質(zhì)也是一棵二叉樹溉知,所以紅黑樹的插入操作與普通二叉樹相同,只是為了維護紅黑樹的性質(zhì)腕够,需要進行節(jié)點顏色變更以及樹旋轉(zhuǎn)(如果需要的話)着倾。

對于新插入的節(jié)點,我們將其標(biāo)記為紅色節(jié)點(如果設(shè)為黑色燕少,就會導(dǎo)致根到葉子節(jié)點的路徑上有一條路多出一個額外的黑節(jié)點。但是設(shè)為紅色節(jié)后蒿囤,沒有多出黑色節(jié)點客们,雖然可能會出現(xiàn)兩個連續(xù)的紅色節(jié)點,但是可以通過顏色調(diào)換和樹旋轉(zhuǎn)來調(diào)整)材诽,對于插入操作需要進行什么操作(顏色變更和樹旋轉(zhuǎn))底挫,取決于其他臨近節(jié)點的顏色。為了方便閱讀后面的代碼脸侥,下面給出一些基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu)以及方法:

type (
    color uint //顏色
    
    //添加的元素
    Element interface {
        Value() interface{}
        Compare(Element) int //相等返回0建邓,小于返回負數(shù),大于返回正數(shù)
    }

    //紅黑樹節(jié)點
    RedBlackNode struct {
        Color  color         //節(jié)點顏色
        Data   Element       //數(shù)據(jù)
        Parent *RedBlackNode //父節(jié)點
        Left   *RedBlackNode //左孩子
        Right  *RedBlackNode //右孩子
    }
    
    //紅黑樹
    RedBlackTree struct {
        Root *RedBlackNode //根節(jié)點
    }
)

const (
    Black color = iota + 1
    Red
)

//獲取某個節(jié)點的祖父節(jié)點(爺爺節(jié)點)
func (t *RedBlackNode) grandParent() *RedBlackNode {
    //根節(jié)點沒有父節(jié)點和祖父節(jié)點
    if t.Parent == nil {
        return nil
    }
    return t.Parent.Parent
}

//獲取某個節(jié)點的叔父節(jié)點(父節(jié)點的兄弟節(jié)點)
func (t *RedBlackNode) uncleNode() *RedBlackNode {
    if t.grandParent() == nil {
        return nil
    }
    if t.Parent == t.grandParent().Left {
        return t.grandParent().Right
    }
    return t.grandParent().Left
}

在添加節(jié)點的過程中:

  1. 性質(zhì)1和性質(zhì)3總是保持著睁枕。
  2. 性質(zhì)4只在增加紅色節(jié)點官边、重繪黑色節(jié)點為紅色沸手,或做旋轉(zhuǎn)時收到威脅。
  3. 性質(zhì)5只在增加黑色節(jié)點注簿、重繪紅色節(jié)點為黑色契吉,或做旋轉(zhuǎn)時收到威脅。

為了方便描述诡渴,在添加節(jié)點操作中捐晶,我們將要插入的節(jié)點標(biāo)為N,N的父節(jié)點標(biāo)為P妄辩,N的祖父節(jié)點標(biāo)為G惑灵,N的叔父節(jié)點標(biāo)為U,下面分情形討論插入節(jié)點的情況:

  1. 節(jié)點N位于樹的根上眼耀,沒有父節(jié)點英支。在這種情形下,我們把N重繪為黑色以滿足性質(zhì)2畔塔,因為它在每個路徑上對黑節(jié)點數(shù)量加1潭辈,符合性質(zhì)5。所以這種情況我們只需要將節(jié)點N重繪為黑色即可澈吨,如果N不位于根上把敢,則進入情形2。
func insertCase1(node *RedBlackNode) (root *RedBlackNode) {
     if node.Parent == nil {
          node.Color = Black
          root = node
          return     
      }
      return insertCase2(node)
}
  1. N的父節(jié)點P是黑色谅辣,因為新節(jié)點是紅色修赞,所以性質(zhì)4沒有失效。因為沒有黑色節(jié)點的增加桑阶,所以在這種情形下性質(zhì)5仍然保持柏副,雖然N有可能有兩個黑色葉子節(jié)點,但是仔細想一想蚣录,如果N有兩個葉子節(jié)點割择,那么在添加節(jié)點前N的位置一定是黑色葉子節(jié)點,所以在添加前后萎河,通過該位置的到達任意葉子節(jié)點的黑色節(jié)點數(shù)目始終未變荔泳,所以性質(zhì)5始終保持著。如果N的父節(jié)點為紅色虐杯,則進入情形3玛歌。
    func insertCase2(node *RedBlackNode) (root *RedBlackNode) {
        if node.Parent.Color == Black {
            return 
        }
        return insertCase3(node)
    }

除了上面兩種情形,在接下來的情形中擎椰,N的父節(jié)點均為紅色支子,所以N一定有祖父節(jié)點(如果沒有祖父節(jié)點,那么父節(jié)點即為根結(jié)點达舒,這與父節(jié)點為紅色節(jié)點不相符)值朋,并且N一定有叔父節(jié)點(叔父節(jié)點可能是沒有數(shù)據(jù)的黑色葉子節(jié)點)叹侄。

  1. 如果父節(jié)點P和叔父節(jié)點U二者均為紅色,則我們可以將P和U重繪為黑色并將祖父節(jié)點G重繪為紅色(為了保持性質(zhì)5)⊥碳撸現(xiàn)在N有了一個黑色的父節(jié)點P圈膏,因為通過父節(jié)點P或者叔父節(jié)點U的任何路徑都必定通過祖父節(jié)點G,所以總的來說這些路徑上的黑色節(jié)點數(shù)量沒有變篙骡。但如果祖父節(jié)點G為根結(jié)點稽坤,那么就違背了性質(zhì)2,也有可能祖父節(jié)點G的父節(jié)點也是紅色糯俗,那么就違背了性質(zhì)4尿褪,為了解決這兩個隱患,我們在祖父節(jié)點G上遞歸的進行情形1整個過程(即把祖父節(jié)點G當(dāng)成新加入的節(jié)點進行各種情形的檢查)得湘。

注意:在情形3中杖玲,無論N作為P的左孩子還是右孩子出現(xiàn),處理過程都一樣

    func insertCase3(node *RedBlackNode) (root *RedBlackNode) {
        if uncle := node.uncleNode(); uncle != nil && uncle.Color == Red {
            grandParent := node.grandParent()
            node.Parent.Color = Black
            uncle.Color = Black
            grandParent.Color = Red
            return insertCase1(grandParent)
        }
        return insertCase4(node)
    }    
  1. 父節(jié)點P是紅色而叔父節(jié)點U是黑色或者缺少淘正,并且N是P的右孩子而P又是G的左孩子摆马,在這種情況下,我們進行一次左旋轉(zhuǎn)調(diào)節(jié)N和P的角色鸿吆,接著我們按情形5處理P以解決仍然失效的性質(zhì)4囤采。
    func insertCase4(node *RedBlackNode) (root *RedBlackNode) {
        grandParent := node.grandParent()
        if node == node.Parent.Right && node.Parent == grandParent.Left {
            leftRotate(node.Parent)
            node = node.Left
        } else if node == node.Parent.Left && node.Parent == grandParent.Right {
            rightRotate(node.Parent)
            node = node.Right
        }
        return insertCase5(node)
    }
  1. 父節(jié)點P是紅色而叔父節(jié)點U是黑色或者缺少,N是P的左孩子惩淳,而P也是G的左孩子蕉毯,這種情形下,我們針對G進行一次右旋轉(zhuǎn)思犁,在旋轉(zhuǎn)產(chǎn)生的樹中代虾,以前的父節(jié)點P現(xiàn)在是N和G的父節(jié)點,因為G肯定是黑色激蹲,所以我們交換P和G的顏色棉磨,交換后的樹滿足性質(zhì)4和性質(zhì)5,因為通過這三個節(jié)點中任何一個的所有路徑以前都通過G学辱,現(xiàn)在它們都通過P含蓉,無論哪種情形下,P現(xiàn)在都是三個節(jié)點中的唯一一個黑色節(jié)點项郊。
    func insertCase5(node *RedBlackNode) (root *RedBlackNode) {
        grandParent := node.grandParent()
        node.Parent.Color = Black
        grandParent.Color = Red
        if node == node.Parent.Left && node.Parent == grandParent.Left {
            root = rightRotate(grandParent)
        } else {
            root = leftRotate(grandParent)
        }
        return
    }

紅黑樹刪除節(jié)點

刪除節(jié)點時,我們需要先找到需要被刪除的節(jié)點斟赚。對于左右孩子均為葉子節(jié)點的着降,如果被刪除的節(jié)點為紅色,則直接將節(jié)點刪除即可拗军,但如果被刪除的節(jié)點是黑色任洞,因為路徑上的黑色節(jié)點數(shù)量少了一個蓄喇,所以需要對樹做調(diào)整以維持各性質(zhì)不變。如果被刪除節(jié)點存在一個葉子節(jié)點和一個子樹交掏,那么從子樹中找到最大或者最小值的節(jié)點妆偏,并將其值復(fù)制到被刪除的節(jié)點,最終將被復(fù)制的節(jié)點刪除即可盅弛,被刪除的節(jié)點最多只有一個非葉子節(jié)點的孩子節(jié)點钱骂。如果被刪除節(jié)點存在左右子樹,我們同樣可以從子樹中找到最大或者最小的值挪鹏,并將其復(fù)制到需要刪除的節(jié)點见秽,并將被復(fù)制的節(jié)點刪除即可,綜上讨盒,刪除問題最終都可以轉(zhuǎn)換成刪除只有一個非葉子節(jié)點的孩子節(jié)點的問題解取。(注意:上面說的復(fù)制只是復(fù)制值而不復(fù)制節(jié)點顏色)。

所以返顺,我們只需要討論刪除只有一個兒子(非葉子)的節(jié)點:

  1. 如果被刪除節(jié)點為紅色禀苦,此時該節(jié)點只有葉子節(jié)點,因為它的父親和孩子節(jié)點都為黑色遂鹊,所以只需要用它的孩子節(jié)點替換它即可振乏。

  2. 如果被刪除節(jié)點是黑色,而它的孩子節(jié)點為紅色的時候稿辙,如果用它的孩子節(jié)點頂替上來的話昆码,會破壞性質(zhì)5,但是如果重繪它的兒子節(jié)點為黑色邻储,則曾經(jīng)通過它的所有路徑將通過它的黑色兒子赋咽,這樣可以繼續(xù)保持性質(zhì)5。

  3. 如果被刪除節(jié)點和它的孩子節(jié)點均為黑色的時候(這種情況下吨娜,該節(jié)點的兩個孩子節(jié)點均為葉子節(jié)點脓匿,因為如果其中一個不為葉子節(jié)點,則從該節(jié)點通過其非葉子節(jié)點的路徑上的黑色節(jié)點數(shù)最少為2宦赠,而從該節(jié)點到另一個葉子節(jié)點的黑色節(jié)點數(shù)量為1陪毡,違反了性質(zhì)5,所以不成立勾扭,即這種情況下該節(jié)點的兩個孩子節(jié)點一定是葉子節(jié)點毡琉。)我們首先把要刪除的節(jié)點替換為它的兒子,出于方便妙色,稱呼這個兒子為N桅滋,稱呼它的兄弟(它父親的另一個兒子)為S。在后面的示意圖中PN的父親,S_L為S的左兒子, S_R為S的右兒子丐谋,其中P才是需要刪除的節(jié)點芍碧,下面為獲取某個節(jié)點兄弟節(jié)點的函數(shù)以及刪除節(jié)點函數(shù)的入口:

//找到某個節(jié)點的兄弟節(jié)點
func (t *RedBlackNode) siblingNode() *RedBlackNode {
    if t.Parent == nil {
        return nil
    }
    if t == t.Parent.Left {
        return t.Parent.Right
    }
    return t.Parent.Left
}

//刪除node節(jié)點, 這里被刪除的節(jié)點一定最多只有一個非葉子節(jié)點的孩子節(jié)點,
func deleteNode(node *RedBlackNode) (root *RedBlackNode) {
    var child *RedBlackNode
    if node.Left.Data == nil {
        child = node.Right
    } else {
        child = node.Left
    }
    //如果刪除的是沒有子樹的根節(jié)點
    if node.Parent == nil && node.Left.Data == nil && node.Right.Data == nil {
        node.Data = nil
        node.Color = Black
        root = node
        return
    }
    //將孩子節(jié)點提升, 這里已經(jīng)將node刪除
    if node.Parent.Left == node {
        node.Parent.Left = child
    } else {
        node.Parent.Right = child
    }
    child.Parent = node.Parent

    //如果node為紅色号俐,刪除紅色節(jié)點不會影響紅黑樹的性質(zhì)泌豆,不需要調(diào)整
    //如果node是黑色,但孩子節(jié)點是紅色吏饿,此時只需要將孩子節(jié)點改為黑色即可
    //如果node是黑色叠蝇,孩子節(jié)點也是黑色狞贱,則少了一個黑色節(jié)點,需要對樹進行調(diào)整,以達到平衡
    if node.Color == Black {
        if child.Color == Red { //如果刪除的是黑色節(jié)點并且提升的孩子節(jié)點為紅色谢床,則只需要將孩子節(jié)點調(diào)色為黑色即可
            child.Color = Black
        } else { //否則需要其他操作
            root = deleteCase1(child)
        }
    }
    return
}
  1. N是新的根烦味,此時樹的所有性質(zhì)都沒有被改變礁鲁,所以不需要操作箍铭,否則進入情形2。
    //被刪除的是根蜜唾,孩子節(jié)點作為新的根杂曲,否則進入case2
    func deleteCase1(node *RedBlackNode) (root *RedBlackNode) {
        if node.Parent == nil {
            return node
        }
        return deleteCase2(node)
    }
  1. N的兄弟節(jié)點S是紅色,這種情形下我們在N的父親節(jié)點P上做左旋轉(zhuǎn)袁余,把兄弟節(jié)點S轉(zhuǎn)換為N的祖父節(jié)點擎勘,接著我們對調(diào)P和祖父的顏色,之后雖然所有路徑上的黑色節(jié)點數(shù)量沒有改變颖榜,但現(xiàn)在N有了一個黑色的兄弟和一個紅色的父親棚饵,我們接著按照情形4、5掩完、6來處理噪漾。
    func deleteCase2(node *RedBlackNode) (root *RedBlackNode) {
        var siblingNode = node.siblingNode()
        if siblingNode == nil {
            return
        }
    
        if siblingNode.Color == Red {
            node.Parent.Color = Red
            siblingNode.Color = Black
            if node == node.Parent.Left {
                leftRotate(node.Parent)
            } else {
                rightRotate(node.Parent)
            }
        }
        return deleteCase3(node)
    }
  1. N的父親,S和S的兒子都是黑色的且蓬。在這種情況下欣硼,我們簡單的重繪S為紅色,結(jié)果是通過S的所有路徑(就是之前不通過N的那些路徑)恶阴,都少了一個黑色節(jié)點诈胜,因為刪除N的初始父親已經(jīng)使通過N的所有路徑少了一個黑色節(jié)點來,所以二者平衡冯事。但是所有通過P的路徑比不通過P的路徑少了一個黑色節(jié)點焦匈,我們可以重復(fù)情形1來重新恢復(fù)平衡。
    func deleteCase3(node *RedBlackNode) (root *RedBlackNode) {
        var siblingNode = node.siblingNode()
    
        if (node.Parent.Color == Black) &&
            (siblingNode.Color == Black) &&
            (siblingNode.Left.Color == Black) &&
            (siblingNode.Right.Color) == Black {
            siblingNode.Color = Red
            return deleteCase1(node.Parent)
        } else {
            return deleteCase4(node)
        }
    }
  1. S和S的兒子都是黑色昵仅,但是N的父親是紅色缓熟。這種情形下,我們簡單的交換N的兄弟和父親的顏色。這不影響不通過N的路徑上的黑色節(jié)點的數(shù)量荚虚。但是通過N的路徑上的黑色節(jié)點數(shù)量增加了1,填補了已經(jīng)被刪除了的黑色節(jié)點籍茧。
    func deleteCase4(node *RedBlackNode) (root *RedBlackNode) {
        var siblingNode = node.siblingNode()
    
        if (node.Parent.Color == Red) &&
            (siblingNode.Color == Black) &&
            (siblingNode.Left.Color == Black) &&
            (siblingNode.Right.Color == Black) {
            siblingNode.Color = Red
            node.Parent.Color = Black
        } else {
            root = deleteCase5(node)
        }
        return
    }
  1. S是黑色版述,S的左孩子是紅色,S的右孩子是黑色寞冯,而N是它父親的左兒子渴析,在這種情形下,我們在S上做右旋轉(zhuǎn)吮龄,這樣S的左兒子將成為S的父親和N的親兄弟俭茧。我們接著交換S和它的新父親的顏色,這樣所有路徑上仍有同樣數(shù)目的黑色節(jié)點漓帚,但是現(xiàn)在N有了一個黑色兄弟母债,它的右孩子是紅色的,接著進入情形6尝抖。
    func deleteCase5(node *RedBlackNode) (root *RedBlackNode) {
        var siblingNode = node.siblingNode()
    
        if siblingNode.Color == Black {
            if (node == node.Parent.Left) &&
                (siblingNode.Right.Color == Black) &&
                (siblingNode.Left.Color == Red) {
                siblingNode.Color = Red
                siblingNode.Left.Color = Black
                rightRotate(siblingNode)
            } else if (node == node.Parent.Right) &&
                (siblingNode.Left.Color == Black) &&
                (siblingNode.Right.Color == Red) {
                siblingNode.Color = Red
                siblingNode.Right.Color = Black
                leftRotate(siblingNode)
            }
        }
        return deleteCase6(node)
    }
  1. S是黑色毡们,S的右孩子是紅色,而N是它父親的左孩子昧辽,在這種情形下衙熔,我們在N的父親上做左旋轉(zhuǎn),這樣S成為N的祖父節(jié)點搅荞,我們接著交換N的父親和S的顏色红氯,并使S的右孩子為黑色。子樹在它的跟上仍然是同樣的顏色咕痛,所以性質(zhì)3沒有打破痢甘,但是N現(xiàn)在增加了一個黑色祖先:要么N的父親變成黑色,要么它是黑色而S被增加為一個黑色祖父暇检。所以通過N的路徑上都增加了一個黑色節(jié)點产阱。此時,如果一個路徑不通過N块仆,則有兩種可能性:

    *. 它通過N的新兄弟构蹬。那么它以前和現(xiàn)在都必定通過S和N的福清,而它們只是交換了顏色悔据,所以路徑保持了同樣數(shù)目的黑色節(jié)點庄敛。
    *. 它通過N的新叔父,S的右孩子科汗,那么它以前通過S藻烤、S的父親和S的右孩子,但是現(xiàn)在只通過S,它被假定為它以前的父親的顏色怖亭,和S的右孩子涎显,它從紅色變?yōu)榱撕谏罱K效果是這個路徑通過了同樣數(shù)目的黑色節(jié)點兴猩。

    在任何情況下期吓,這些路徑上的黑色節(jié)點數(shù)目都沒有改變。在圖中的白色節(jié)點可以是紅色或黑色倾芝。

 func deleteCase6(node *RedBlackNode) (root *RedBlackNode) {
        var siblingNode = node.siblingNode()
    
        siblingNode.Color = node.Parent.Color
        node.Parent.Color = Black
    
        if node == node.Parent.Left {
            siblingNode.Right.Color = Black
            root = leftRotate(node.Parent)
        } else {
            siblingNode.Left.Color = Black
            root = rightRotate(node.Parent)
        }
        return
    }

不論插入還是刪除節(jié)點讨勤,最終都返回了一個root,因為在旋轉(zhuǎn)過程中樹的根結(jié)點有可能發(fā)生改變晨另,所以需要將每次旋轉(zhuǎn)后的最頂層的節(jié)點返回潭千,并最終與原來的root節(jié)點比較,如果不同則做替換借尿。

參考文獻

《Wiki》

最后

原文鏈接

謝謝閱讀刨晴,此處為源碼

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末垛玻,一起剝皮案震驚了整個濱河市割捅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌帚桩,老刑警劉巖亿驾,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異账嚎,居然都是意外死亡莫瞬,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門郭蕉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來疼邀,“玉大人,你說我怎么就攤上這事召锈∨哉瘢” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵涨岁,是天一觀的道長拐袜。 經(jīng)常有香客問我,道長梢薪,這世上最難降的妖魔是什么蹬铺? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮秉撇,結(jié)果婚禮上甜攀,老公的妹妹穿的比我還像新娘秋泄。我一直安慰自己,他們只是感情好规阀,可當(dāng)我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布恒序。 她就那樣靜靜地躺著,像睡著了一般谁撼。 火紅的嫁衣襯著肌膚如雪奸焙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天彤敛,我揣著相機與錄音,去河邊找鬼了赌。 笑死墨榄,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的勿她。 我是一名探鬼主播袄秩,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼逢并!你這毒婦竟也來了之剧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤砍聊,失蹤者是張志新(化名)和其女友劉穎背稼,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體玻蝌,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡蟹肘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了俯树。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片帘腹。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖许饿,靈堂內(nèi)的尸體忽然破棺而出阳欲,到底是詐尸還是另有隱情,我是刑警寧澤陋率,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布球化,位于F島的核電站,受9級特大地震影響翘贮,放射性物質(zhì)發(fā)生泄漏赊窥。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一狸页、第九天 我趴在偏房一處隱蔽的房頂上張望锨能。 院中可真熱鬧扯再,春花似錦、人聲如沸址遇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽倔约。三九已至秃殉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間浸剩,已是汗流浹背钾军。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留绢要,地道東北人吏恭。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像重罪,于是被迫代替她去往敵國和親樱哼。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,612評論 2 350