初探Java源碼之LinkedList

上篇文章我們分析了常見的ArrayList源碼茅郎,它的內(nèi)部是由一個(gè)數(shù)組來實(shí)現(xiàn)的患雏。那么今天,我們來分析另一個(gè)常見的類LinkedList捏萍。本文分析都來自Java8太抓。

(ps:這段話寫自寫完本文記錄后添加。個(gè)人感想為已經(jīng)寫成了介紹鏈表)


類說明

不多廢話令杈,首先我們來看一下這個(gè)類走敌。

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
    transient int size = 0;

    /**
     * Pointer to first node.
     * Invariant: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)
     */
    transient Node<E> first;

    /**
     * Pointer to last node.
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    transient Node<E> last;

從LinkedList這個(gè)類名我們就猜出,這個(gè)List內(nèi)部可能是由鏈表來實(shí)現(xiàn)逗噩,我們后面來驗(yàn)證一下掉丽。它實(shí)現(xiàn)了Deque接口跌榔,因此可以知道,LinkedList也可以作為隊(duì)列來進(jìn)行使用机打。同時(shí)也實(shí)現(xiàn)了Serializable接口矫户,說明可以對(duì)它進(jìn)行序列化,反序列化來傳遞残邀,獲取數(shù)據(jù)等等皆辽。
我們?cè)賮砜纯碙inkedList的成員變量。首先是一個(gè)int類型的size,這個(gè)我們?cè)贏rrayList中也介紹過芥挣。這個(gè)是一個(gè)表明List有多少個(gè)元素驱闷。然后是一個(gè)Node類型的first變量,從注釋我們看出指向頭結(jié)點(diǎn)的變量(用C空免,C++解釋稱之為指針空另,也許用C語(yǔ)言的方式更好解釋)。后面的last變量也很好理解蹋砚,它指向最后結(jié)點(diǎn)扼菠。我們跟進(jìn)Node類去看看源碼:

    private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

這是一個(gè)LinkedList的內(nèi)部類,還是比較簡(jiǎn)單的坝咐。首先一個(gè)泛型的item變量循榆,用來存儲(chǔ)數(shù)據(jù),然后有一個(gè)指向下一個(gè)結(jié)點(diǎn)的next指針墨坚,前一個(gè)結(jié)點(diǎn)的prev指針秧饮。

至此我們其實(shí)就可以得出結(jié)論,LinkedList果然名不虛傳泽篮,內(nèi)部就是由鏈表的形式實(shí)現(xiàn)盗尸。它并沒有用數(shù)組來存儲(chǔ)數(shù)據(jù)元素,而是由一個(gè)個(gè)Node類型結(jié)點(diǎn)來儲(chǔ)存數(shù)據(jù)帽撑,然后每個(gè)Node結(jié)點(diǎn)通過指向前后結(jié)點(diǎn)的next和prev指針將整個(gè)List串聯(lián)起來泼各。我們來畫張簡(jiǎn)單圖來看看ArrayList和LinkedList的基本區(qū)別:

ArrayList和LinkedList區(qū)別

正是這樣的區(qū)別,從而導(dǎo)致了兩者不同的效率問題亏拉。如果我們對(duì)一個(gè)ArrayList頻繁的增加數(shù)據(jù)历恐,那么內(nèi)部的數(shù)組就會(huì)不斷擴(kuò)容創(chuàng)建新的數(shù)組然后把舊數(shù)據(jù)復(fù)制到新數(shù)組返回。插入數(shù)據(jù)或者刪除其中一個(gè)數(shù)據(jù)专筷,又要把所有數(shù)據(jù)后移或者前移。這樣的操作效率很低下的蒸苇,為了一個(gè)數(shù)據(jù)處理了其他數(shù)據(jù)磷蛹。

而LinkedList不同,插入只需要將要插入位置的前結(jié)點(diǎn)的next指針指向新的數(shù)據(jù)結(jié)點(diǎn)(如下圖插入工作圖的2)溪烤,將插入結(jié)點(diǎn)的prev指向前指針(如1處)味咳,將next指向下一個(gè)結(jié)點(diǎn)(如3處)庇勃,將之前的后結(jié)點(diǎn)的prev指針指向插入指針(如4處)。刪除也是如下刪除工作圖槽驶,就不再講述责嚷。這樣的話只需要幾步操作就完成了處理,無需移動(dòng)大量數(shù)據(jù)掂铐。效率非常高罕拂。(下面兩幅圖均來自網(wǎng)上大神的鏈表介紹文章http://www.cnblogs.com/bb3q/p/4490589.html)無恥的借用一下下~~~

插入工作圖

刪除工作圖

那既然如此ArrayList豈不是一無是處了?為啥還要用呢全陨?其實(shí)并不是爆班,鏈表既然是用指針的方式連起來,那么意味著我們尋找某個(gè)結(jié)點(diǎn)就需要從頭開始遍歷辱姨,直到找到這個(gè)元素為止柿菩,并不能提供隨機(jī)訪問。例如我們想找數(shù)組的第五個(gè)元素雨涛,那么只需xxx[4]即可得到枢舶,但是鏈表不行,只能從頭開始遍歷到第五個(gè)元素才行替久。因此在開發(fā)中如果需要對(duì)list頻繁的添加凉泄,刪除,插入侣肄,那么用LinkedList是很好的旧困。但是數(shù)據(jù)量不大,需要經(jīng)常查詢數(shù)據(jù)的時(shí)候稼锅,ArrayList更適合吼具。

至此我們就將LinkedList的類和成員變量介紹完了,也分析了和ArrayList的區(qū)別矩距。接下來我們來看看構(gòu)造方法:

    public LinkedList() {
    }

    /**
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     *
     * @param  c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
    }

第一個(gè)構(gòu)造方法是空實(shí)現(xiàn)拗盒,因?yàn)閮?nèi)部是鏈表,無需像ArrayLsi一樣t實(shí)例化數(shù)組锥债。

我們來看看第二個(gè)構(gòu)造方法陡蝇,傳入?yún)?shù)為一個(gè)集合,主要是調(diào)用了addAll()方法哮肚,我們來看看:

 public boolean addAll(Collection<? extends E> c) {
        return addAll(size, c);
    }

 public boolean addAll(int index, Collection<? extends E> c) {
        checkPositionIndex(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        if (numNew == 0)
            return false;

        Node<E> pred, succ;
        if (index == size) {
            succ = null;
            pred = last;
        } else {
            succ = node(index);
            pred = succ.prev;
        }

        for (Object o : a) {
            @SuppressWarnings("unchecked") E e = (E) o;
            Node<E> newNode = new Node<>(pred, e, null);
            if (pred == null)
                first = newNode;
            else
                pred.next = newNode;
            pred = newNode;
        }

        if (succ == null) {
            last = pred;
        } else {
            pred.next = succ;
            succ.prev = pred;
        }

        size += numNew;
        modCount++;
        return true;
    }

第一個(gè)addAll()方法將size傳入登夫,其實(shí)就是從原有List的末尾開始添加傳入的數(shù)據(jù),而這里size為0允趟。所以就是從頭開始添加數(shù)據(jù)恼策。我們仔細(xì)分析第二個(gè)addAll()方法。

我們拆開來分析:

 private void checkPositionIndex(int index) {
        if (!isPositionIndex(index))
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

首先checkPositionIndex()方法來判斷傳入的index是否大于0并且小于size潮剪。

   Object[] a = c.toArray();
        int numNew = a.length;
        if (numNew == 0)
            return false;

        Node<E> pred, succ;
        if (index == size) {
            succ = null;
            pred = last;
        } else {
            succ = node(index);
            pred = succ.prev;
        }

然后將傳入的集合首先轉(zhuǎn)換為數(shù)組涣楷。然后判斷數(shù)組長(zhǎng)度是否為0分唾,如果是0,表示沒有添加的數(shù)據(jù)狮斗,直接返回绽乔。

如果不是,那么定義兩個(gè)結(jié)點(diǎn)succ和pred碳褒。個(gè)人理解succ表示要插入的index下標(biāo)的結(jié)點(diǎn)折砸,pred表示succ結(jié)點(diǎn)的前結(jié)點(diǎn)。然后判斷index是否等于size,而我們?cè)跇?gòu)造方法中傳入的index就等于size,所以表示從鏈表的末尾開始添加數(shù)據(jù)骤视。即succ為null(因?yàn)橄聵?biāo)從0開始鞍爱,所以最后一個(gè)數(shù)據(jù)下標(biāo)為size - 1),pred為last最后一個(gè)結(jié)點(diǎn)。如果index不等于size,那么找到index處的結(jié)點(diǎn)賦值給succ,pred等于succ的前結(jié)點(diǎn)专酗。

 for (Object o : a) {
            @SuppressWarnings("unchecked") E e = (E) o;
            Node<E> newNode = new Node<>(pred, e, null);
            if (pred == null)
                first = newNode;
            else
                pred.next = newNode;
            pred = newNode;
        }

到這里就已經(jīng)把預(yù)處理工作完成了睹逃。接下來就是添加數(shù)據(jù)過程。首先是一個(gè)for循環(huán)遍歷a數(shù)組祷肯。每個(gè)對(duì)象(也就是數(shù)據(jù))都生成一個(gè)結(jié)點(diǎn)沉填。然后將新結(jié)點(diǎn)的前指針指向pred結(jié)點(diǎn)。如果pred為空(這種情況就是鏈表為空佑笋,沒有一個(gè)結(jié)點(diǎn))翼闹,那么這個(gè)新結(jié)點(diǎn)就是鏈表的表頭。如果pred不為空蒋纬,那么將pred的后指針指向這個(gè)新結(jié)點(diǎn)猎荠。這樣就將pred結(jié)點(diǎn)和新結(jié)點(diǎn)串聯(lián)起來。然后pred往后移一個(gè)結(jié)點(diǎn)蜀备,指向新結(jié)點(diǎn)关摇。這樣就不斷的將所有新數(shù)據(jù)插入到指點(diǎn)位置往后。

 if (succ == null) {
            last = pred;
        } else {
            pred.next = succ;
            succ.prev = pred;
        }

for循環(huán)后碾阁,會(huì)判斷succ是否為空(即我們插入位置的舊結(jié)點(diǎn)是否為空)输虱。如果為空,表明我們是插入到鏈表的末尾的脂凶,那么就無需將舊結(jié)點(diǎn)的后結(jié)點(diǎn)的prev指針修改(因?yàn)楦緵]后結(jié)點(diǎn))宪睹,直接將last指向pred(因?yàn)樵趂or循環(huán)中pred會(huì)指向新數(shù)據(jù)集合的最后一個(gè)數(shù)據(jù))即可。如果succ不為空蚕钦,表示我們是在鏈表的中間插入數(shù)據(jù)的亭病。因此就要將新數(shù)據(jù)集合的最后一個(gè)數(shù)據(jù)結(jié)點(diǎn)的next后指針指向我們插入位置的結(jié)點(diǎn)。然后將未插入前的index處的結(jié)點(diǎn)的前結(jié)點(diǎn)修改為指向新插入的最后一個(gè)數(shù)據(jù)結(jié)點(diǎn)即pred嘶居。

        size += numNew;
        modCount++;
        return true;

最后將數(shù)據(jù)數(shù)量加上新插入的數(shù)據(jù)數(shù)量命贴,修改數(shù)據(jù)結(jié)構(gòu)次數(shù)自加1即可。

至此我們就已經(jīng)將構(gòu)造方法分析完畢,可以說就是最常見的數(shù)據(jù)結(jié)構(gòu)中雙向鏈表的操作方法胸蛛。接下來我們繼續(xù)分析一些常見的方法。


add()

我們來看看最常用的幾個(gè)add()方法,首先是第一個(gè):

  public boolean add(E e) {
        linkLast(e);
        return true;
    }

我們看到就是調(diào)用了linkLast()方法樱报,我們跟進(jìn)去看看:

 void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }

我們來看看這個(gè)方法葬项,首先定義了兩個(gè)常量l和newNode結(jié)點(diǎn)。分別表示鏈表中最后一個(gè)結(jié)點(diǎn)和一個(gè)封裝了新數(shù)據(jù)的新結(jié)點(diǎn)迹蛤。新結(jié)點(diǎn)的前指針指向l民珍。然后將last指針指向新結(jié)點(diǎn)。然后判斷如果l結(jié)點(diǎn)(即之前的最后一個(gè)結(jié)點(diǎn))是空盗飒,表明鏈表之前沒有數(shù)據(jù)嚷量,加入的新數(shù)據(jù)將會(huì)稱為第一個(gè)結(jié)點(diǎn)。因此將表頭first指針指向新結(jié)點(diǎn)逆趣。如果l不為空蝶溶。則將之前最后一個(gè)結(jié)點(diǎn)的后指針指向新結(jié)點(diǎn),新結(jié)點(diǎn)指向l宣渗。然后size自加1抖所,modCount自加1表示修改了一次鏈表。這樣就將新數(shù)據(jù)插入到了鏈表的末尾痕囱。

第二個(gè)add()方法:

public void add(int index, E element) {
        checkPositionIndex(index);

        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
    }

首先是調(diào)用checkPositionIndex()方法檢查index是否大于0并小于size田轧。
然后如果index等于size,表示我們要將數(shù)據(jù)插入到鏈表的末尾鞍恢,調(diào)用linkLast()方法來插入數(shù)據(jù),上面分析了該方法這里就不在贅述傻粘。如果index不等于size,那么表示是在鏈表的中間插入數(shù)據(jù),那么調(diào)用linkBefore()方法:

  void linkBefore(E e, Node<E> succ) {
        // assert succ != null;
        final Node<E> pred = succ.prev;
        final Node<E> newNode = new Node<>(pred, e, succ);
        succ.prev = newNode;
        if (pred == null)
            first = newNode;
        else
            pred.next = newNode;
        size++;
        modCount++;
    }

可以看到其實(shí)也是差不多的,首先定義兩個(gè)常量Node變量pred和newNode用來表示我們要插入的結(jié)點(diǎn)的前結(jié)點(diǎn)和一個(gè)要插入的新結(jié)點(diǎn)帮掉,這個(gè)新結(jié)點(diǎn)的前指針指向pred,后指針指向插入位置的舊結(jié)點(diǎn)弦悉。然后將要插入位置的舊結(jié)點(diǎn)的prev前指針指向新結(jié)點(diǎn)。如果pred為空旭寿,表示我們要插入的位置是表頭警绩,直接將表頭指針first指向新結(jié)點(diǎn)。如果不為空盅称,那么將pred的后指針next指向新結(jié)點(diǎn)肩祥。

remove()

 public boolean remove(Object o) {
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }

我們來看看第一個(gè)remove()方法,傳入的參數(shù)表示是一個(gè)數(shù)據(jù)缩膝。雖然要首先判斷我們傳入的數(shù)據(jù)是否為空來分開操作混狠。但是其實(shí)都是一樣的做遍歷然后刪除結(jié)點(diǎn)。如果是空疾层,那么就要進(jìn)行for循環(huán)從表頭開始遍歷将饺,有人可能會(huì)好奇,傳入為空的話為什么還要找,沒有意義呀予弧?這里我的想法是鏈表是一種數(shù)據(jù)結(jié)構(gòu)刮吧,它是以結(jié)點(diǎn)為基礎(chǔ)存在的,不關(guān)心數(shù)據(jù)掖蛤。所以有可能某個(gè)結(jié)點(diǎn)不為空杀捻,但是結(jié)點(diǎn)封裝的數(shù)據(jù)為空。因此蚓庭,在某些特殊場(chǎng)景下萬一有些人就是要存空數(shù)據(jù)呢致讥?我們重點(diǎn)看看unlink()方法:

 E unlink(Node<E> x) {
        // assert x != null;
        final E element = x.item;
        final Node<E> next = x.next;
        final Node<E> prev = x.prev;

        if (prev == null) {
            first = next;
        } else {
            prev.next = next;
            x.prev = null;
        }

        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }

        x.item = null;
        size--;
        modCount++;
        return element;
    }

首先將要?jiǎng)h除結(jié)點(diǎn)的數(shù)據(jù)取出。然后得到刪除結(jié)點(diǎn)的前結(jié)點(diǎn)prev器赞,后結(jié)點(diǎn)next垢袱。然后如果前結(jié)點(diǎn)為空,表明刪除結(jié)點(diǎn)為頭結(jié)點(diǎn)港柜,因此直接將表頭first指針指向刪除結(jié)點(diǎn)的后結(jié)點(diǎn)请契。否則的話將prev的next指針直接跳過刪除結(jié)點(diǎn)指向next結(jié)點(diǎn)。然后將輸出結(jié)點(diǎn)的prev指針置空潘懊。后面的next判空也是同理姚糊。最后將刪除結(jié)點(diǎn)的數(shù)據(jù)置空,鏈表數(shù)量自減1授舟,modCount自加1救恨,然后刪除結(jié)點(diǎn)的數(shù)據(jù)。至此释树,結(jié)點(diǎn)刪除就已經(jīng)完成肠槽。
接下來我們來看看第二個(gè)remove()方法:

public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }

這個(gè)更簡(jiǎn)單,移除指定的結(jié)點(diǎn)奢啥。還是首先檢查index的合法性秸仙,然后得到指定位置的結(jié)點(diǎn)調(diào)用unlink()方法移除即可。上面已分析unlink()方法桩盲,就不再贅述寂纪。
第三個(gè)remove()方法:

 public E remove() {
        return removeFirst();
    }

說實(shí)話這個(gè)remove()方法我不是很理解為什么這些寫,就是調(diào)用removeFirst()方法來移除表頭結(jié)點(diǎn)赌结。百思不得其解為什么要這么設(shè)計(jì)捞蛋,而且remove()這個(gè)方法名也根本看不出是移除表頭的意思。也沒有什么可以分析的柬姚,就是一個(gè)簡(jiǎn)單的移除表頭結(jié)點(diǎn)拟杉。

clear()

  public void clear() {
        // Clearing all of the links between nodes is "unnecessary", but:
        // - helps a generational GC if the discarded nodes inhabit
        //   more than one generation
        // - is sure to free memory even if there is a reachable Iterator
        for (Node<E> x = first; x != null; ) {
            Node<E> next = x.next;
            x.item = null;
            x.next = null;
            x.prev = null;
            x = next;
        }
        first = last = null;
        size = 0;
        modCount++;
    }

我們來看看clear()方法,顧名思義量承,clear就是將鏈表清空搬设。所以直接一個(gè)for循環(huán)穴店,從表頭開始一直到表尾。將每個(gè)結(jié)點(diǎn)的數(shù)據(jù)直接置空即可拿穴。最后將表頭泣洞,表尾first,last置空。size置為0即可贞言。

get()

  public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }

get()方法也很常用斜棚,我們來看看,首先調(diào)用checkElementIndex()方法檢查index是否大于0并小于size该窗。然后調(diào)用了node()方法來獲取指定位置的結(jié)點(diǎn)。我們?nèi)タ纯矗?/p>

Node<E> node(int index) {
        // assert isElementIndex(index);

        if (index < (size >> 1)) {
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }

我們看到蚤霞,這里還是用了一點(diǎn)小技巧酗失。首先判斷我們想要的位置是否是在鏈表的前半部分還是后半部分(size >> 1 表示除以2),如果在前半部分那么就從表頭開始遍歷昧绣,在后半部分就從表尾開始往前遍歷规肴。知道拿到目標(biāo)結(jié)點(diǎn)即可。

set()

 public E set(int index, E element) {
        checkElementIndex(index);
        Node<E> x = node(index);
        E oldVal = x.item;
        x.item = element;
        return oldVal;
    }

首先也是調(diào)用checkElementIndex()方法檢查index是否大于0并小于size夜畴。然后也是調(diào)用node()方法獲取指定位置的結(jié)點(diǎn)拖刃。然后將指定結(jié)點(diǎn)的item數(shù)據(jù)置為新值,返回舊值即可贪绘。

至此我們常見的LinkedList的方法源碼分析就已經(jīng)完了兑牡,其他的一些方法要么不怎么用,要么非常簡(jiǎn)單只有一兩行簡(jiǎn)單代碼甚至就是調(diào)用這些常見方法税灌,讀者一跟進(jìn)去就能明白均函,這里就不再深究。


最后我們?cè)賮砜偨Y(jié)一下:

首先LinkedList內(nèi)部是由雙向鏈表來實(shí)現(xiàn)的菱涤。我們儲(chǔ)存的每一個(gè)數(shù)據(jù)都會(huì)被封裝在一個(gè)數(shù)據(jù)結(jié)點(diǎn)之中苞也。而結(jié)點(diǎn)瘋轉(zhuǎn)了指向前結(jié)點(diǎn)的指針,數(shù)據(jù)粘秆,指向后結(jié)點(diǎn)的指針如迟。依靠這些數(shù)據(jù)結(jié)點(diǎn)實(shí)現(xiàn)雙向鏈表。
既然是鏈表攻走,那么優(yōu)點(diǎn)就是添加殷勘,插入,刪除數(shù)據(jù)效率比數(shù)組高很多陋气。因?yàn)樵诓迦牖蛘邉h除某個(gè)數(shù)據(jù)時(shí)劳吠,只需對(duì)要?jiǎng)h除結(jié)點(diǎn),前結(jié)點(diǎn)巩趁,后結(jié)點(diǎn)進(jìn)行操作痒玩,無需像數(shù)組一樣將后續(xù)數(shù)據(jù)全部前移或者后移淳附。但是由此也看出缺點(diǎn),因?yàn)殒湵聿⒉皇沁B續(xù)的空間儲(chǔ)存蠢古,也沒有什么下標(biāo)進(jìn)行記錄位置奴曙。因此要尋找某個(gè)數(shù)據(jù)時(shí)只能進(jìn)行遍歷,而不像數(shù)組一樣可以隨機(jī)查找草讶。如果我們?cè)趯?shí)際開發(fā)中我們需要對(duì)某個(gè)List進(jìn)行頻繁的插入洽糟,刪除,而且數(shù)據(jù)量又特別大的時(shí)候堕战±だ#可以考慮使用LinkedList。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末嘱丢,一起剝皮案震驚了整個(gè)濱河市薪介,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌越驻,老刑警劉巖汁政,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異缀旁,居然都是意外死亡记劈,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門并巍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來目木,“玉大人,你說我怎么就攤上這事履澳∷徽” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵距贷,是天一觀的道長(zhǎng)柄冲。 經(jīng)常有香客問我,道長(zhǎng)忠蝗,這世上最難降的妖魔是什么现横? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮阁最,結(jié)果婚禮上戒祠,老公的妹妹穿的比我還像新娘。我一直安慰自己速种,他們只是感情好姜盈,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著配阵,像睡著了一般馏颂。 火紅的嫁衣襯著肌膚如雪示血。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天救拉,我揣著相機(jī)與錄音难审,去河邊找鬼。 笑死亿絮,一個(gè)胖子當(dāng)著我的面吹牛告喊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播派昧,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼黔姜,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了蒂萎?” 一聲冷哼從身側(cè)響起地淀,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎岖是,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體实苞,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡豺撑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了黔牵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片聪轿。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖猾浦,靈堂內(nèi)的尸體忽然破棺而出陆错,到底是詐尸還是另有隱情,我是刑警寧澤金赦,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布音瓷,位于F島的核電站,受9級(jí)特大地震影響夹抗,放射性物質(zhì)發(fā)生泄漏绳慎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一漠烧、第九天 我趴在偏房一處隱蔽的房頂上張望杏愤。 院中可真熱鬧,春花似錦已脓、人聲如沸珊楼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)厕宗。三九已至画舌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間媳瞪,已是汗流浹背骗炉。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蛇受,地道東北人句葵。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像兢仰,于是被迫代替她去往敵國(guó)和親乍丈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容