JavaScript--排序算法的可視化動畫

2017/3/26 17:03 更新
我把一大堆算法的代碼放最后了胰伍,要不影響閱讀乱顾,要看的同學(xué)去最后找


正文開始

這個題目,老早就知道了肛循,但是當(dāng)時因為忙著學(xué)習(xí)別的東西,雖然感覺挺有趣银择,但是一直也沒著手去做多糠。這幾天在補全排序算法的知識,剛好欢摄,也把這個給做了出來熬丧。

下邊是demo笋粟,和代碼地址

demo演示
github代碼

簡介

首先簡單分析下問題怀挠,大概有這幾個點需要解決

  • 排序算法
  • 動畫
  • 如何將算法用動畫展示

很顯然析蝴,第三點是最難的。

想要實現(xiàn)這個绿淋,首先要會排序算法闷畸,關(guān)于常用的排序算法,在文章里就不在多說吞滞,這個不是我們的重點佑菩,我僅僅貼出我寫的算法代碼。

動畫其實也很簡單裁赠,用css設(shè)置一些過度效果殿漠,比如顏色啊,漸漸消失佩捞,漸漸出現(xiàn)啊绞幌,之類的。也不多說一忱,大家可以隨意發(fā)揮莲蜘。我做的,只設(shè)置了顏色的漸變帘营。

我們重點分析票渠,如何將算法的每一步用動畫展示。

如果你對排序算法還不太了解芬迄,我把排序算法的基本代碼都用JavaScript寫了一遍问顷,放在文章結(jié)尾。大家可以根據(jù)下文說的禀梳,自行改造择诈,

分析,如何展示算法動畫

如果要把排序過程用柱狀圖變換來表示出皇,很顯然羞芍,也就是說,把對數(shù)組的操作過程郊艘,轉(zhuǎn)變成了對一組dom的操作荷科。

我們對算法都有一定了解了,縱觀來看纱注,實現(xiàn)可視化動畫畏浆,其實就是表現(xiàn)出幾個關(guān)鍵的元素。

  • 每趟的關(guān)鍵目標元素(target——藍色)
  • 正在比較的元素(checked——綠色)
  • 經(jīng)過比較狞贱,需要與target元素進行交換的checked元素(selecked——紅色)

那么如何把上邊這些關(guān)鍵元素刻获,以動畫效果反應(yīng)出來呢?

一上來瞎嬉,我們可能回想蝎毡,那就排一步厚柳,展示一步唄。但是沐兵,排一步别垮,展示一步就等于是讓js引擎走一步,然后暫停js引擎扎谎,再讓渲染引擎走一步碳想,如此循環(huán)往復(fù)直到結(jié)束。但是js引擎開弓沒有回頭箭毁靶,我們還沒有一個方法胧奔,可以讓它先停下來歇一歇。

有的同學(xué)可能說预吆,用定時器葡盗,但是,往深處一想就會發(fā)現(xiàn)定時器是不行的啡浊,它有問題:

  • js引擎單線程觅够,導(dǎo)致使用定時器的結(jié)果跟我們期望的不同。
  • 作用域問題

如果使用定時器巷嚣,必然要大量使用喘先,因為每一步dom操作,都需要一個定時器廷粒,在設(shè)計過程解決上邊的問題窘拯,肯定一頭包。(我當(dāng)時仔細想了想坝茎,就放棄了涤姊,太亂了)

所以,我們要換一個思路

我們都知道嗤放,動畫其實就是一幀一幀的靜態(tài)畫面思喊,也就是一個個狀態(tài)的變換。那么我們其實可以在對純數(shù)組進行排序的過程中次酌,記錄下我們需要的所有幀恨课,然后等排序結(jié)束后,對我們收集到的所有幀岳服,進行從頭到尾的展示

假如我們的html是這樣

<div id="box">
    <div class="item" style="height:54px">54</div>
                ·····
                ·····
</div>

用高度代表了數(shù)字

可以這樣設(shè)計

numArr = box盒子下剂公,所有item的innerHTML轉(zhuǎn)換成數(shù)字(Number()方法)
function sort(arr) {
  var animationArr = [];// 這個數(shù)組用來記錄幀
  // 下邊某個算法的具體過程,在排序的過程中吊宋,記錄幀
  ...

  return animationArr // 將幀數(shù)組返回
}

sort(numArr);

那么幀數(shù)組中的數(shù)據(jù)要怎么設(shè)計呢纲辽?其實我們知道,排序算法都有每一趟,和每一趟的第一步拖吼,第二步鳞上,第三步,.......

而根據(jù)我們的具體動畫需要绿贞,可以做如下設(shè)計

// 最內(nèi)層的對象因块,只是一個例子橘原,是快速排序時候的每幀的可能狀態(tài)籍铁。
animationArr = [
    [
        {
            currentArrStart = undefined,
            currentArrEnd = undefined,
            target = undefined,
            selected = undefined,
            checked = undefined,
            removeSelected = undefined,
        },
        ...
        ...
    ],
    ...
    ...
]

最外層數(shù)組的每一項,表示每一趟趾断;里層數(shù)組的每一項拒名,表示每一步的幀狀態(tài)對象,每種排序算法芋酌,最內(nèi)層的幀狀態(tài)對象的屬性可能是不同的增显,我們可以根據(jù)具體需要來設(shè)計。

我們拿到了幀數(shù)組脐帝,那么如何展現(xiàn)動畫呢同云?

很簡單,一個setInterval()堵腹,每次循環(huán)炸站,就展示一幀,而且疚顷,這樣設(shè)計的話旱易,我們還可以通過控制循環(huán)間隔時間,來實現(xiàn)加快速度腿堤,減慢速度的效果阀坏。

分析結(jié)束

接下來,我就拿快速排序為例子笆檀,來一步步展示忌堂,如何實現(xiàn)它。

以快速排序為例的具體實現(xiàn)過程

  1. 首先酗洒,簡單說下項目結(jié)構(gòu)


    項目結(jié)構(gòu)圖

    很簡單浸船,沒什么復(fù)雜的

  2. html
    我們有這樣的DOM結(jié)構(gòu)

<div id="box">
        <div class="item" style="height:54px">54</div>
        <div class="item" style="height:14px">14</div>
        <div class="item" style="height:77px">77</div>
        <div class="item" style="height:28px">28</div>
        <div class="item" style="height:99px">99</div>
        <div class="item" style="height:65px">65</div>
        <div class="item" style="height:49px">49</div>
        <div class="item" style="height:89px">89</div>
        <div class="item" style="height:21px">21</div>
        <div class="item" style="height:25px">25</div>
        <div class="item" style="height:50px">50</div>
        <div class="item" style="height:80px">80</div>
        <div class="item" style="height:19px">19</div>
        <div class="item" style="height:37px">37</div>
        <div class="item" style="height:31px">31</div>
    </div>
    <div id="sortBtn">
        <button id="quickSortBtn" data-method="quickSort">快速排序動畫</button>
    </div>
  1. css
    其實關(guān)鍵是下邊的四個.item--就是我們在展示動畫過程中要頻繁操作的類名了。
.item {
    padding: 10px 5px;
    background-color: gray;
    color: #fff;
    display: inline-block;
    margin-right: 5px;
    vertical-align: bottom;
    transition: background-color .5s;
}
#box {
  padding: 5px 0;
}
.item--current {
    background-color: skyblue;
}
.item--checked {
    background-color: green;
}
.item--selected {
    background-color: red;
}
.item--target {
    background-color: blue;
}
  1. 排序算法
    對于每種算法寝蹈,其實我們都要實現(xiàn)兩個方法:
  • 傳入純數(shù)字的數(shù)組李命,進行排序,傳出幀數(shù)組
  • 這種排序算法對應(yīng)的dom操作方法

以快速排序為例箫老,快速排序的基本寫法在尾部封字,我們對他改進,保留幀。其實每一種算法都可以這樣做阔籽,大家可以自己試一試流妻。(算法的基本寫法都在尾部)。

function quickSort(arrDom) {
    // 傳遞進來一個Dom類數(shù)組笆制,對其進行排序
    var arr = [],
        animationArr = []; // 這個數(shù)組中绅这,存儲每一次動畫的數(shù)據(jù)

    for (let i = 0, len = arrDom.length; i < len; i++) {
        arr.push(Number(arrDom[i].innerHTML));
    }

    sort(0, arr.length - 1);
    return animationArr;

    function sort(left, right) {
        let i = left, //左游標 右游標
            j = right,
            animationArrStep = [],
            stardard = arr[left];
        animationArrStep.push({
            currentArrStart: left,
            currentArrEnd: right
        });
        animationArrStep.push({
            target: left
        });
        if ((right - left) > 0) {
            while (i < j) {
                for (; i < j; j--) {
                    animationArrStep.push({
                        checked: j
                    });
                    if (arr[j] < stardard) {
                        animationArrStep.push({
                            target: i,
                            selected: j
                        });
                        animationArrStep.push({
                            removeSelected: i
                        });
                        arr[i++] = arr[j];

                        break;
                    }
                }
                for (; i < j; i++) {
                    animationArrStep.push({
                        checked: i
                    });
                    if (arr[i] > stardard) {
                        animationArrStep.push({
                            target: j,
                            selected: i
                        });
                        animationArrStep.push({
                            removeSelected: j
                        });
                        arr[j--] = arr[i];
                        break;
                    }
                }
            }
            arr[i] = stardard;
            animationArr.push(animationArrStep);
            sort(left, i - 1);
            sort(i + 1, right);
        }
    }
}


// 這里是快速排序?qū)?yīng)的dom操作方法,我們在方法形參處設(shè)計了幀狀態(tài)對象的具體內(nèi)容
function quickSortAnimationDom(arrDomBox, {
    currentArrStart = undefined,
    currentArrEnd = undefined,
    // 表示本趟有關(guān)的項的開始和結(jié)尾
    target = undefined,
    selected = undefined,
    checked = undefined,
    removeSelected = undefined, // 用來在交換后在辆,移除selected狀態(tài)证薇。
}) {
    // arrDom 是包裹柱狀圖的盒子,也就是#box
    if (checked !== undefined) {
        arrDomBox.children[checked].classList.add("item--checked");
    } else if (target !== undefined) {
        arrDomBox.children[target].classList.add("item--target");
        if (selected !== undefined) {

            arrDomBox.children[selected].classList.add("item--selected");

            let a = arrDomBox.children[target].cloneNode(true),
                b = arrDomBox.children[selected].cloneNode(true);
            arrDomBox.replaceChild(b, arrDomBox.children[target]);
            arrDomBox.replaceChild(a, arrDomBox.children[selected]);
        }
    } else if (removeSelected !== undefined) {
        arrDomBox.children[removeSelected].classList.remove("item--selected");
    } else if (currentArrStart !== undefined && currentArrEnd !== undefined) {
        for (let i = currentArrStart; i <= currentArrEnd; i++) {
            arrDomBox.children[i].classList.add("item--current");
        }
    }
}

關(guān)于dom算法匆篓,有一點需要說明浑度,

我們傳進來的arrDomBox,是因為鸦概,排序免不了進行dom的交換操作箩张,為了每次都確保我們獲取的是最新的item節(jié)點,而不是插入前的窗市,所以先慷,必須從父節(jié)點出發(fā)尋找。

關(guān)于這一點咨察,有不明白的同學(xué)论熙,可以留言,咱們再討論扎拣。

animation.js動畫相關(guān)

我們需要把它做成一個小模塊赴肚,避免過多的綁定到window上變量,同時二蓝,也避免定時器操作過程中誉券,取變量錯誤。

這個模塊刊愚,我做的比較簡單踊跟,沒有實現(xiàn)很多功能,比如

  • 控制速度大小
  • 自動生成數(shù)組
  • 算法切換

等等吧鸥诽,但是都留有可控制的口子商玫。
比如,速度牡借,大家可以自己做一做拳昌,控制下speed變量就可以了
切換算法也很簡單,不多說了钠龙。

function SortAnimation() {
    this.timer = 0;
    this.arrDomBox = {};
    this.animationArr = [];
    this.speed = 500;
    this.sortMethod = {};
    this.currentMethod = '';
    // sortMethod 的數(shù)據(jù)結(jié)構(gòu)為{method:數(shù)組排序并返回動畫數(shù)組的方法名, animationMethod: dom排序方法名}
}

SortAnimation.prototype = {
    getData: function(arrDomBox, method) {
        this.arrDomBox = arrDomBox;
        this.currentMethod = method;
        this.animationArr = this.sortMethod[method].method(arrDomBox.children);
    },

    ownedMethod: function(methodObj) {
        this.sortMethod = methodObj;
    },

    startAnimation: function() {
        var that = this;
        // 為了保存下,this炬藤,用了閉包御铃,當(dāng)然還有別的處理辦法。
        return function() {
            if (that.animationArr.length === 0) {
                // 清除DOM樣式
                for (let i = 0, len = that.arrDomBox.children.length; i < len; i++) {
                    that.arrDomBox.children[i].classList.remove("item--target", "item--current", "item--selected", "item--checked");
                }
                // 動畫結(jié)束
                clearTimeout(that.timer);
            } else if (that.animationArr[0].length > 0) {
                that.sortMethod[that.currentMethod].animationMethod(that.arrDomBox, that.animationArr[0][0]);
                that.animationArr[0].shift();
            } else {
                // 清除DOM樣式
                for (let i = 0, len = that.arrDomBox.children.length; i < len; i++) {
                    that.arrDomBox.children[i].classList.remove("item--target", "item--current", "item--selected", "item--checked");
                }
                // 進入下一趟排序的動畫
                that.animationArr.shift();
            }
        };
    }
}

window.sa = new SortAnimation();

大家也應(yīng)該看到了沈矿,其實寫的是有一定復(fù)用性的上真。根據(jù)我們寫的,最后就可以調(diào)用了

<script>
        var sortBtn = document.querySelector("#sortBtn");
        
        sa.ownedMethod({
            quickSort: {
                method: quickSort,
                animationMethod: quickSortAnimationDom
            }
        })

        sortBtn.addEventListener("click", function(event) {
            var arrDomBox = document.querySelector("#box");
            // 注意羹膳,一定要是父元素睡互,因為,在替換元素的過程中陵像,被替換元素不會消失就珠,如果在最開始直接引用子元素,那么蠢壹,將無法取到替換后的元素
            sa.getData(arrDomBox, event.target.dataset.method);
            sa.timer = setInterval(sa.startAnimation(), sa.speed);
        });
    </script>

大功告成Iのァ>叛病图贸!

結(jié)語總結(jié)

其實挺有意思的,博主在這只是拋磚引玉冕广,希望大家有興趣可以動手試一試疏日。當(dāng)然,如果有朋友有任何疑問撒汉,請下邊留言告訴我沟优,能力范圍內(nèi),我一定答復(fù)睬辐。

如有什么錯誤挠阁,請一定指正。謝謝了

排序算法的代碼

下邊的算法溯饵,我沒有對他們進行很完善的測試侵俗,只是簡單的試了幾個數(shù)組,如果大家發(fā)現(xiàn)問題丰刊,請留言聯(lián)系我隘谣,我會盡快改正。

  • 冒泡排序
// 冒泡排序啄巧,共三個寻歧,后兩個為改進算法
function bubbleSort(arr) {
    for (let i = 0, len = arr.length; i < len; i++) {
        for (let j = 0; j < len - i; j++) {
            if (arr[j] > arr[j + 1]) {
                [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
                // 解構(gòu)賦值,交換變量值
            }
        }
    }
    return arr;
}

// 改進:記錄交換位置秩仆,提高速度
function bubbleSortPlus(arr) {
    let i = arr.length;
    while (i > 0) {
        var position = 0;
        for (let j = 0; j < i; j++) {
            if (arr[j] > arr[j + 1]) {
                [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
                // 解構(gòu)賦值码泛,交換變量值
                position = j;
            }
        }
        i = position; // 因為,只有position為0時候澄耍,才說明排好了噪珊。
    }
    return arr;
}

// 改進:雙冒泡
function bubbleSortDb(arr) {
    var top = arr.length - 1,
        bottom = 0,
        j;

    while (bottom < top) {
        for (j = bottom; j < top; j++) {
            if (arr[j] > arr[j + 1]) {
                [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
                // 解構(gòu)賦值忘衍,交換變量值
            }
        }
        top--;
        for (; j > bottom; j--) {
            if (arr[j] < arr[j - 1]) {
                [arr[j], arr[j - 1]] = [arr[j - 1], arr[j]];
                // 解構(gòu)賦值,交換變量值
            }
        }
        bottom++;
    }
    return arr;
}
  • 選擇排序
// 選擇排序
function selectSort(arr) {
    var minIndex;
    for (let i = 0, len = arr.length; i < len; i++) {
        minIndex = i;
        for (let j = i + 1; j < len; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
        [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
    }
    return arr;
}
  • 插入排序
// 插入排序 卿城,后邊有二分優(yōu)化后的
function insertionSort(arr) {
    for (let i = 1, len = arr.length; i < len; i++) {
        let keyNum = arr[i],
            j = i - 1;
        while (j >= 0 && arr[j] > keyNum) {
            arr[j + 1] = arr[j];
            j--;
        }
        arr[j + 1] = keyNum;
    }
    return arr;
}

// 二分查找優(yōu)化 插入排序
function binaryInsertionSort(arr) {
    for (let i = 1, len = arr.length; i < len; i++) {
        let keyNum = arr[i],
            left = 0,
            right = i - 1;

        // 此處枚钓,要考慮兩邊界時候,出現(xiàn)的問題瑟押,不能簡單的left < right搀捷,當(dāng)在右邊界時候,left需要再移動一位多望。
        while (left <= right) {
            let middle = Math.floor((left + right) / 2);
            if (keyNum > arr[middle]) {
                left = middle + 1;
            } else {
                right = middle - 1;
            }
        }
        // 比left大的嫩舟,向右位移一位
        for (let j = i - 1; j >= left; j--) {
            arr[j + 1] = arr[j];
        }
        arr[left] = keyNum;
    }

    return arr;
}
  • 希爾排序
/ 希爾排序
function shellSort(arr) {
    let len = arr.length,
        gap = Math.ceil(Math.floor(len / 2) / 2) * 2 - 1;
    for (; gap > 0; gap = gap - 2) {
        for (let i = gap; i < len; i++) {
            let keyNum = arr[i],
                j = i - gap;
            while (j >= 0 && arr[j] > keyNum) {
                arr[j + gap] = arr[j];
                j = j - gap;
            }
            arr[j + gap] = keyNum;
        }
    }

    return arr;
}
  • 歸并排序
// 歸并排序
function mergerSort(arr) {
    let len = arr.length;
    if (len < 2) {
        return arr;
    }
    let middle = Math.floor(len / 2),
        left = arr.slice(0, middle),
        right = arr.slice(middle);
    return merger(mergerSort(left), mergerSort(right));
}

function merger(left, right) {
    var arr = [];
    while (left.length && right.length) {
        if (left[0] <= right[0]) {
            arr.push(left.shift());
        } else {
            arr.push(right.shift());
        }
    }
    while (left.length) {
        arr.push(left.shift());
    }
    while (right.length) {
        arr.push(right.shift());
    }
    return arr;
}
  • 快速排序
// 快速排序
function quickSort(arr) {
    sort(0, arr.length - 1);
    return arr;

    function sort(left, right) {
        let i = left, //左游標 右游標
            j = right,
            stardard = arr[left];

        if ((right - left) > 0) {
            while (i < j) {
                for (; i < j; j--) {
                    if (arr[j] < stardard) {
                        arr[i++] = arr[j];
                        break;
                    }
                }
                for (; i < j; i++) {
                    if (arr[i] > stardard) {
                        arr[j--] = arr[i];
                        break;
                    }
                }
            }
            arr[i] = stardard;
            sort(left, i - 1);
            sort(i + 1, right);
        }
    }
}
  • 堆排序
/ 堆排序
function heapSort(arr) {

    function heapify(arr, i, unorderedHeapSize) {
        let largest = i,
            leftChild = 2 * i + 1,
            rightChild = 2 * i + 2;
        if (leftChild < unorderedHeapSize && arr[leftChild] > arr[largest]) {
            largest = leftChild;
        }
        if (rightChild < unorderedHeapSize && arr[rightChild] > arr[largest]) {
            largest = rightChild;
        }
        if (largest != i) {
            swap(arr, i, largest);
            heapify(arr, largest, unorderedHeapSize);
        }

    }

    function swap(arr, x, y) {
        [arr[x], arr[y]] = [arr[y], arr[x]];
    }

    function buildMaxHeap(arr) {
        for (let i = Math.floor(arr.length / 2) - 1; i >= 0; i--) {
            heapify(arr, i, arr.length);
        }
    }

    // 建堆
    buildMaxHeap(arr);

    // 堆排序
    for (let i = arr.length - 1; i > 0; i--) {
        swap(arr, 0, i);
        heapify(arr, 0, i);
    }
    return arr;

}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市怀偷,隨后出現(xiàn)的幾起案子家厌,更是在濱河造成了極大的恐慌,老刑警劉巖椎工,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饭于,死亡現(xiàn)場離奇詭異,居然都是意外死亡维蒙,警方通過查閱死者的電腦和手機掰吕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來颅痊,“玉大人殖熟,你說我怎么就攤上這事“呦欤” “怎么了菱属?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長舰罚。 經(jīng)常有香客問我纽门,道長,這世上最難降的妖魔是什么沸停? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任膜毁,我火速辦了婚禮,結(jié)果婚禮上愤钾,老公的妹妹穿的比我還像新娘瘟滨。我一直安慰自己,他們只是感情好能颁,可當(dāng)我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布杂瘸。 她就那樣靜靜地躺著,像睡著了一般伙菊。 火紅的嫁衣襯著肌膚如雪败玉。 梳的紋絲不亂的頭發(fā)上敌土,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天,我揣著相機與錄音运翼,去河邊找鬼返干。 笑死,一個胖子當(dāng)著我的面吹牛血淌,可吹牛的內(nèi)容都是我干的矩欠。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼悠夯,長吁一口氣:“原來是場噩夢啊……” “哼癌淮!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起沦补,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤乳蓄,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后夕膀,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體虚倒,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年店诗,在試婚紗的時候發(fā)現(xiàn)自己被綠了裹刮。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片音榜。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡庞瘸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出赠叼,到底是詐尸還是另有隱情擦囊,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布嘴办,位于F島的核電站瞬场,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏涧郊。R本人自食惡果不足惜贯被,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望妆艘。 院中可真熱鬧彤灶,春花似錦、人聲如沸批旺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽汽煮。三九已至搏熄,卻和暖如春棚唆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背心例。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工宵凌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人止后。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓摆寄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親坯门。 傳聞我的和親對象是個殘疾皇子微饥,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,472評論 2 348

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,749評論 25 707
  • 選擇qi:是表達式 標簽選擇器 類選擇器 屬性選擇器 繼承屬性: color,font古戴,text-align欠橘,li...
    love2013閱讀 2,304評論 0 11
  • 選擇qi:是表達式 標簽選擇器 類選擇器 屬性選擇器 繼承屬性: color,font现恼,text-align肃续,li...
    wzhiq896閱讀 1,732評論 0 2
  • 最近行動派總部完成的社群的整理。 把已經(jīng)卸任的圈主叉袍,還有長期潛水的伙伴抱出社群大家庭始锚,新的有活力的伙伴申請加入。 ...
    幸運花開隨筆閱讀 306評論 13 8
  • “她結(jié)婚了喳逛,好像瞧捌,”莫特跟身邊的小戀說,顯得漫不經(jīng)心润文,從小棉再一次離開他以后姐呐,他就是這樣,對什么事都是一副漫不經(jīng)心...
    一心小記閱讀 312評論 0 3