數(shù)據(jù)結(jié)構(gòu):棧與隊(duì)列

本文內(nèi)容:
一械媒、棧
1目锭、什么是棧评汰?
2纷捞、棧的操作集.
3、棧的 C 實(shí)現(xiàn).

二被去、隊(duì)列
1主儡、什么是隊(duì)列?
2惨缆、隊(duì)列的操作集.
3糜值、隊(duì)列的 C 實(shí)現(xiàn).

總表:《數(shù)據(jù)結(jié)構(gòu)?》

工程代碼 Github: Data_Structures_C_Implemention -- Stack & Queue


一坯墨、棧

1寂汇、什么是棧?

棧 (Stack)捣染,是限制插入與刪除操作只能在末端 (Top) 進(jìn)行的表骄瓣,而這個(gè)末端也稱為棧頂;

它有時(shí)候也會被稱為耍攘,先進(jìn)后出 (LIFO: Last In First Out) 表;

棧的抽象模型圖:

2榕栏、棧的操作集.

從上面的模型圖中就可以看出,棧的核心操作有: Push蕾各、Pop扒磁、Top (Peek) 三個(gè)操作;

棧操作集圖示:
棧 操作集.png

3式曲、棧的 C 實(shí)現(xiàn).

棧的實(shí)現(xiàn)方式妨托,有兩類,

解析:
1吝羞、數(shù)組的實(shí)現(xiàn)方式始鱼,我覺得不需要過多的解釋了遮婶,鏈表就是為了解決數(shù)組的缺點(diǎn)而被設(shè)計(jì)出來的盒音;
那么為什么要使用單鏈表來實(shí)現(xiàn)表神僵,而不是其它鏈表形式呢卷胯?

首先枢析,單鏈表是所有鏈表里面最簡單的鏈表坞淮,空間占用也是最小的耀里,也就是開銷最芯伦浮筒捺;只要證明單鏈表可以實(shí)現(xiàn)即可以了柏腻。

棧是一個(gè)表,而且是只能在一個(gè)端口進(jìn)行插入與刪除操作系吭,遍歷方向是從棧底到棧頂五嫂;
而單鏈表也是一個(gè)表,而且它的操作可以在任意位置進(jìn)行插入與刪除,遍歷方向是鏈頭與鏈尾沃缘;

從上面的兩個(gè)結(jié)論來看躯枢,棧可以看作是單鏈表的其中一種情況槐臀;

2锄蹂、在這里 tail 指針的指向改了一下,把它放在鏈頭 [一般習(xí)慣性左邊是指鏈頭] 而它指向的就是最后一個(gè)壓入的節(jié)點(diǎn)水慨,也就是說左邊的第一個(gè)節(jié)點(diǎn)就是真正的鏈尾得糜;這樣設(shè)計(jì)的目的就是為了讓鏈表可以從鏈尾直接進(jìn)行遍歷操作,而且所有的插入與刪除操作在鏈尾就可以實(shí)現(xiàn)晰洒;【您如果覺得暈朝抖,就先保有疑惑,等到查看下面的棧的入棧與出棧操作的具體代碼實(shí)現(xiàn)的時(shí)候谍珊,我相信您就懂了槽棍!】

  • 節(jié)點(diǎn)[內(nèi)存結(jié)構(gòu)]與棧的定義:

節(jié)點(diǎn)[內(nèi)存結(jié)構(gòu)],

struct __StackNode {
    ElementTypePrt data;
#if _C_STACK_LINKEDLIST_IMP
    StackNode next;
#else
    int prevIdx;
#endif
};

解析:
1抬驴、_C_STACK_LINKEDLIST_IMP 原型是 #define _C_STACK_LINKEDLIST_IMP 1 就是一個(gè)宏開關(guān)炼七,1 的時(shí)候是使用單鏈表的方式實(shí)現(xiàn)棧,0 就是使用數(shù)組的方式實(shí)現(xiàn)棧布持;

2豌拙、ElementTypePrt 原型是 typedef void * ElementTypePrt;,使用 typedef 是方便后期進(jìn)行修改题暖;這里使用指針的目的是為了讓鏈表支持更多的數(shù)據(jù)類型按傅,使代碼的可擴(kuò)展性更強(qiáng);【如: data 可以直接指向一個(gè)單純的 int 或者 一個(gè) struct 胧卤,又或者是一個(gè) list 等等】

3唯绍、在數(shù)組實(shí)現(xiàn)的方式下,prevIdx 這個(gè)參量其實(shí)可以不要的枝誊,看君愛好吧况芒,反正入棧、出棧與它無關(guān)叶撒;

棧绝骚,

typedef struct __StackNode * _StackNode;
typedef _StackNode StackNode;

typedef struct __Stack * _Stack;
typedef _Stack Stack;

struct __Stack {
    unsigned int size;
    MatchFunc matchFunc;
    DestroyFunc destroyFunc;
#if _C_STACK_LINKEDLIST_IMP
    StackNode tail;
#else 
    unsigned int capacity;
    int tailIdx;
    StackNode nodes;
#endif
};

解析:
1、鏈表實(shí)現(xiàn)方式下祠够,

#if _C_STACK_LINKEDLIST_IMP
    StackNode tail;
#else 

是取消了 head 指針压汪,只保留了單鏈表的 tail 指針;

2古瓤、數(shù)組實(shí)現(xiàn)方式下止剖,

#else 
    unsigned int capacity;
    unsigned int tailIdx;
    StackNode nodes;
#endif

引入一個(gè) capacity 參量腺阳,我們知道,C 語言中數(shù)組初始化是要指定長度的穿香,而這個(gè)參量就是表明數(shù)組的最大長度亭引,也就是可以存儲多少個(gè)節(jié)點(diǎn);

tailIdx 就是棧頂節(jié)點(diǎn)的下標(biāo)扔水;
nodes 是一個(gè)結(jié)構(gòu)體指針痛侍,相當(dāng)于一個(gè)數(shù)組的首指針朝氓,數(shù)組中保存的是 struct __StackNode魔市;

  • 棧的核心操作集:
/* Stack Create */
#if _C_STACK_LINKEDLIST_IMP
    Stack Stack_Create(DestroyFunc des);
#else
    Stack Stack_Create(unsigned int cap, DestroyFunc des);
#endif

void Stack_Init(Stack s, DestroyFunc des);
void Stack_Destroy(Stack s);

/* Stack Operations */
_BOOL Stack_Push(Stack s, ElementTypePrt x);
_BOOL Stack_Pop(Stack s, ElementTypePrtPrt data);
ElementTypePrt Stack_Peek(Stack s);
_BOOL Stack_PeekAndPop(Stack s, ElementTypePrtPrt data);
  • 棧的創(chuàng)建與銷毀:

創(chuàng)建,
【鏈?zhǔn)綄?shí)現(xiàn)】Stack Stack_Create(DestroyFunc des);

Stack Stack_Create(DestroyFunc des) {

    Stack s = (Stack)(malloc(sizeof(struct __Stack)));
    if (s == NULL) { printf("ERROR: Out Of Space !"); return NULL; }

    Stack_Init(s, des);

    return s;

}

解析:
1赵哲、DestroyFunc 原型是 typedef void(*DestroyFunc) (void * data); 指向形如 void(*) (void * data); 的函數(shù)指針待德;data 如何進(jìn)行釋放也由使用者決定;也是為了代碼可擴(kuò)展性枫夺;

2将宪、malloc 原型是 void * malloc(size_t size)

3橡庞、Stack_Init(s, des);较坛,請移步面下面的解釋 初始化

【數(shù)組實(shí)現(xiàn)】Stack Stack_Create(unsigned int cap, DestroyFunc des);

Stack Stack_Create(unsigned int cap, DestroyFunc des) {

    if (cap == 0) { printf("ERROR: Bad Cap Parameter [cap > 0] !"); return NULL; }
    if (cap > STACK_MAXELEMENTS) { printf("ERROR: Bad Cap Parameter [cap < STACK_MAXELEMENTS(%d)] !", STACK_MAXELEMENTS); return NULL; }

    Stack s = (Stack)(malloc(sizeof(struct __Stack)));
    if (s == NULL) { printf("ERROR: Out Of Space !"); return NULL; }

    s->nodes = malloc(sizeof(StackNode) * cap);
    if (s->nodes == NULL) { printf("ERROR: Out Of Space !"); free(s); return NULL; }

    s->capacity = cap;
    Stack_Init(s, des);

    return s;

}

解析:
1扒最、形參 unsigned int cap 就是數(shù)組初始化的最大內(nèi)存空間丑勤;

2、STACK_MAXELEMENTS 原型是 #define STACK_MAXELEMENTS 100;

3吧趣、s->nodes = malloc(sizeof(StackNode) * cap); 這里就是與鏈?zhǔn)綄?shí)現(xiàn)最大的區(qū)別法竞,提前申請要保存節(jié)點(diǎn)的內(nèi)存空間;

4强挫、Stack_Init(s, des);岔霸,請移步面下面的解釋 初始化

初始化俯渤,

void Stack_Init(Stack s, DestroyFunc des) {

    if (s == NULL) { printf("ERROR: Please Using Stack_Create(...) First !"); return; }

    s->size = LINKEDLIST_EMPTY;
    s->matchFunc = NULL;
    s->destroyFunc = des;
#if _C_STACK_LINKEDLIST_IMP
    s->tail = NULL;
#else
    s->tailIdx = STACK_INVAILDINDEX;
#endif

}

解析呆细,
里面的參量直接進(jìn)行賦值為空就可以了,其中 LINKEDLIST_EMPTY 原型是 #define LINKEDLIST_EMPTY 0八匠,STACK_INVAILDINDEX 原型是 #define STACK_INVAILDINDEX -1;

銷毀侦鹏,

void Stack_Destroy(Stack s) {
    
    if (s == NULL) { printf("ERROR: Please Using Stack_Create(...) First !"); return; }

    ElementTypePrt data;

    while (!Stack_IsEmpty(s)) {
        if ((Stack_Pop(s, (ElementTypePrtPrt)&data) == LINKEDLIST_TRUE) &&
            (s->destroyFunc != NULL)) {

            s->destroyFunc(data);
        }
    }

    memset(s, 0, sizeof(struct __Stack));

}

解析,運(yùn)作原理是不停地做出棧處理臀叙,直到椔运空為止,就是清空棧的作用劝萤;
1渊涝、Stack_IsEmpty(s) 原型是 _BOOL Stack_IsEmpty(Stack s) { return (s->size == LINKEDLIST_EMPTY); }

2、Stack_Pop(s, (ElementTypePrtPrt)&data) == LINKEDLIST_TRUE) 請移步下面的 出棧操作

  • 入棧操作:
_BOOL Stack_Push(Stack s, ElementTypePrt x) {

    if (s == NULL) { printf("ERROR: Please Using Stack_Create(...) First !"); return LINKEDLIST_FALSE; }

    StackNode nNode;
    nNode = malloc(sizeof(struct __StackNode));
    if (nNode == NULL) { printf("ERROR: Out Of Space ! "); return LINKEDLIST_FALSE; }

    nNode->data = x;

#if _C_STACK_LINKEDLIST_IMP

    nNode->next = NULL;

    if (Stack_IsEmpty(s)) {
        s->tail = nNode;
    } else {

        /* Get Tail */
        StackNode tail = s->tail;

        /* Push Operations */
        nNode->next = tail;

        /* Set Tail */
        s->tail = nNode;

    }

    /* Size ++ */
    s->size++;

#else 

    /* Size ++ */
    s->size++;

    if (s->size > s->capacity) { 
        printf("ERROR: Out Of Space ! ");
        s->size--;
        return LINKEDLIST_FALSE;
    }

    nNode->prevIdx = s->tailIdx;

    s->tailIdx++;
    s->nodes[s->tailIdx] = *nNode;

#endif

    return LINKEDLIST_TRUE;

}

解析,

入棧操作圖示跨释,

【鏈?zhǔn)綄?shí)現(xiàn)】
// 對應(yīng)的核心代碼
【鏈?zhǔn)綄?shí)現(xiàn)】
nNode->next = tail;
s->tail = nNode;

【數(shù)組實(shí)現(xiàn)】
// 對應(yīng)的核心代碼
【數(shù)組實(shí)現(xiàn)】
s->tailIdx++;
s->nodes[s->tailIdx] = *nNode;
  • 出棧操作:
_BOOL Stack_Pop(Stack s, ElementTypePrtPrt data) {

    if (s == NULL) { printf("ERROR: Bad Stack !"); return LINKEDLIST_FALSE; }
    if (Stack_IsEmpty(s)) { printf("ERROR: Empty Stack !"); return LINKEDLIST_FALSE; }

#if _C_STACK_LINKEDLIST_IMP

    StackNode lDelete = s->tail;

    /* Get Data */
    *data = lDelete->data;

    /* Pop Operations */
    s->tail = s->tail->next;

    /* Free The Deleted Node */
    free(lDelete);

#else

    *data = s->nodes[s->tailIdx].data;
    s->tailIdx--;

#endif

    /* Size -- */
    s->size--;

    return LINKEDLIST_TRUE;

}

解析胸私,

出棧操作圖示,

【鏈?zhǔn)綄?shí)現(xiàn)】
// 對應(yīng)的核心代碼
StackNode tail = s->tail;
s->tail = s->tail->next;

free(lDelete);

【數(shù)組實(shí)現(xiàn)】
// 對應(yīng)的核心代碼
s->tailIdx--;

二鳖谈、隊(duì)列

1岁疼、什么是隊(duì)列?

隊(duì)列 (Queue)缆娃,是限制插入操作在一端捷绒,而刪除操作要在另一端進(jìn)行的表;

它有時(shí)候也會被稱為贯要,先進(jìn)先出 (FIFO: First In First Out) 表;

隊(duì)列的抽象模型圖:

2暖侨、隊(duì)列的操作集.

從上面的模型圖中就可以看出,隊(duì)列的核心操作集有: Enqueue崇渗、Dequeue 兩個(gè)操作字逗;

隊(duì)列操作集圖示:
隊(duì)列 操作集.png

3、隊(duì)列的 C 實(shí)現(xiàn).

隊(duì)列其實(shí)更接近單鏈表了宅广,具備頭和尾葫掉,當(dāng)然遍歷方向也是從頭到尾,所以直接使用單鏈表來實(shí)現(xiàn)就可以了跟狱,不需要做太多的修改俭厚;

不過這里的,數(shù)組實(shí)現(xiàn)就要有點(diǎn)技巧了兽肤;

因?yàn)殛?duì)列是一個(gè)端口進(jìn)套腹,另一個(gè)端口出,也就是要有一個(gè)指向進(jìn)入方向的下標(biāo) headIdx 资铡,以及出方向的下標(biāo) tailIdx 电禀;

這里要注意的是, headIdxtailIdx 的大小關(guān)系是不定的笤休,這是由于數(shù)組自初始化后尖飞,空間是固定的,而在頻繁的入隊(duì)與出隊(duì)操作后店雅,會出現(xiàn) headIdx > tailIdx 政基、headIdx < tailIdxheadIdx = tailIdx '這三種情況闹啦,而且它們會不停地進(jìn)行切換沮明;【當(dāng)然這里也是要在代碼實(shí)現(xiàn)的時(shí)候要特別細(xì)心處理的地方】

  • 節(jié)點(diǎn)[內(nèi)存結(jié)構(gòu)]與隊(duì)列的定義:

節(jié)點(diǎn),【與棧節(jié)點(diǎn)定義一致】

typedef struct __QueueNode * _QueueNode;
typedef _QueueNode QueueNode;

struct __QueueNode {
    ElementTypePrt data;
#if _C_QUEUE_LINKEDLIST_IMP
    QueueNode next;
#else
    int prevIdx;
#endif
};

隊(duì)列窍奋,

typedef struct __Queue * _Queue;
typedef _Queue Queue;

struct __Queue {
    unsigned int size;
    MatchFunc matchFunc;
    DestroyFunc destroyFunc;
#if _C_QUEUE_LINKEDLIST_IMP
    QueueNode head;
    QueueNode tail;
#else 
    unsigned int capacity;
    int headIdx;
    int tailIdx;
    QueueNode nodes;
#endif
};

解析荐健,
與棧對比酱畅,鏈?zhǔn)綄?shí)現(xiàn)下,重新引入 QueueNode head; 指針江场,用于進(jìn)行出隊(duì)的操作纺酸;數(shù)組實(shí)現(xiàn)下,引入 int headIdx; 方便進(jìn)行出隊(duì)操作址否;

  • 隊(duì)列核心操作集:
/* Queue Create */
#if _C_QUEUE_LINKEDLIST_IMP
  Queue Queue_Create(DestroyFunc des);
#else
  Queue Queue_Create(unsigned int cap, DestroyFunc des);
#endif

void Queue_Init(Queue q, DestroyFunc des);
void Queue_Destroy(Queue q);

/* Queue Operations */
_BOOL Queue_Enqueue(Queue q, ElementTypePrt x);
_BOOL Queue_Dequeue(Queue q, ElementTypePrtPrt data);
ElementTypePrt Queue_Peek(Queue q);
_BOOL Queue_PeekAndDequeue(Queue q, ElementTypePrtPrt data);

解析餐蔬,_C_QUEUE_LINKEDLIST_IMP 原型是 #define _C_QUEUE_LINKEDLIST_IMP 1 鏈?zhǔn)綄?shí)現(xiàn)或數(shù)組實(shí)現(xiàn)的開關(guān);

  • 隊(duì)列的創(chuàng)建與銷毀:

創(chuàng)建佑附,這里的代碼實(shí)現(xiàn)與棧的實(shí)現(xiàn)一致樊诺;

初始化,

void Queue_Init(Queue q, DestroyFunc des) {
    
    if (q == NULL) { printf("ERROR: Please Using Queue_Create(...) First !"); return; }

    q->size = LINKEDLIST_EMPTY;
    q->matchFunc = NULL;
    q->destroyFunc = des;
#if _C_QUEUE_LINKEDLIST_IMP
    q->tail = NULL;
#else
    q->headIdx = 0;
    q->tailIdx = QUEUE_INVAILDINDEX;
#endif

}

解析帮匾,這里要注意的是啄骇,在 數(shù)組實(shí)現(xiàn)方式下痴鳄,

#else
    q->headIdx = 0;
    q->tailIdx = QUEUE_INVAILDINDEX; // -1
#endif

headIdx = 0 這里選擇 0 而不是 QUEUE_INVAILDINDEX瘟斜,因?yàn)檫@樣做在入隊(duì)操作的時(shí)候就可以使用headIdx 而不用增加一個(gè)判斷【您可以先留有疑惑,結(jié)合下面的入隊(duì)操作痪寻,我相信您就懂了】螺句;

銷毀,
與棧的出棧操作原理上是一樣橡类,只不過這里使用的是隊(duì)列的出隊(duì)操作罷了蛇尚;

void Queue_Destroy(Queue q) {
    
    if (q == NULL) { printf("ERROR: Please Using Queue_Create(...) First !"); return; }

    ElementTypePrt data;

    while (!Queue_IsEmpty(q)) {
        if ((Queue_Dequeue(q, (ElementTypePrtPrt)&data) == LINKEDLIST_TRUE) &&
            (q->destroyFunc != NULL)) {

            q->destroyFunc(data);
        }
    }

    memset(q, 0, sizeof(struct __Queue));

}
  • 入隊(duì)操作:
_BOOL Queue_Enqueue(Queue q, ElementTypePrt x) {
    
    if (q == NULL) { printf("ERROR: Please Using Queue_Create(...) First !"); return LINKEDLIST_FALSE; }

    QueueNode nNode;
    nNode = malloc(sizeof(struct __QueueNode));
    if (nNode == NULL) { printf("ERROR: Out Of Space ! "); return LINKEDLIST_FALSE; }

    nNode->data = x;

#if _C_QUEUE_LINKEDLIST_IMP

    nNode->next = NULL;

    if (Queue_IsEmpty(q)) {
        q->head = q->tail = nNode;
    } else {

        /* Get Tail */
        QueueNode tail = q->tail;

        /* Push Operations */
        nNode->next = tail->next;
        tail->next = nNode;

        /* Set Tail */
        q->tail = nNode;

    }

    /* Size ++ */
    q->size++;

#else 

    /* Size ++ */
    q->size++;

    if (q->size > q->capacity) {
        printf("ERROR: Out Of Space ! ");
        q->size--;
        return LINKEDLIST_FALSE;
    }

    q->tailIdx = Queue_VaildIdx(q->tailIdx, q);
    nNode->prevIdx = q->tailIdx;

    q->nodes[q->tailIdx] = *nNode;

#endif

    return LINKEDLIST_TRUE;

}

解析,入隊(duì)操作顾画,在鏈?zhǔn)綄?shí)現(xiàn)下就直接在鏈尾進(jìn)行取劫,而數(shù)組實(shí)現(xiàn)下直接在數(shù)組的最后一個(gè)下標(biāo)節(jié)點(diǎn)進(jìn)行;

入隊(duì)操作圖示研侣,

【鏈?zhǔn)綄?shí)現(xiàn)】
// 對應(yīng)的核心代碼
nNode->next = tail->next;
tail->next = nNode;

q->tail = nNode;

【數(shù)組實(shí)現(xiàn)】
// 對應(yīng)的核心代碼
q->tailIdx = Queue_VaildIdx(q->tailIdx, q);
nNode->prevIdx = q->tailIdx;

q->nodes[q->tailIdx] = *nNode;

解析谱邪,這里要注意的是,tailIdx 的取值范圍是 [0 ~ (size - 1) ~ 0] 它是一個(gè)循環(huán)庶诡,而不是簡單地 taildIdx + 1惦银;
Queue_VaildIdx 原型是

int Queue_VaildIdx(int idx, Queue q) {
    if (++idx == q->capacity) { return 0; }
    return idx;
}

提示,++idx == q->capacity 它的運(yùn)算過程是 idx = idx + 1, idx == q->capacity 末誓;

  • 出隊(duì)操作:
_BOOL Queue_Dequeue(Queue q, ElementTypePrtPrt data) {
    
    if (q == NULL) { printf("ERROR: Bad Queue !"); return LINKEDLIST_FALSE; }
    if (Queue_IsEmpty(q)) { printf("ERROR: Empty Queue !"); return LINKEDLIST_FALSE; }

#if _C_QUEUE_LINKEDLIST_IMP

    QueueNode lDelete = q->head;

    /* Get Data */
    *data = lDelete->data;

    /* Pop Operations */
    q->head = q->head->next;

    /* Free The Deleted Node */
    free(lDelete);

#else

    *data = q->nodes[q->headIdx].data;
    q->headIdx = Queue_VaildIdx(q->headIdx, q);

#endif

    /* Size -- */
    q->size--;

    return LINKEDLIST_TRUE;

}

解析扯俱,出隊(duì)操作,在鏈?zhǔn)綄?shí)現(xiàn)下就直接在鏈頭進(jìn)行喇澡,而數(shù)組實(shí)現(xiàn)下直接在數(shù)組的第一個(gè)下標(biāo)節(jié)點(diǎn)進(jìn)行迅栅;

出隊(duì)操作圖示,

【鏈?zhǔn)綄?shí)現(xiàn)】
// 對應(yīng)的核心代碼
QueueNode lDelete = q->head;
q->head = q->head->next;

free(lDelete);

【數(shù)組實(shí)現(xiàn)】
// 對應(yīng)的核心代碼
q->headIdx = Queue_VaildIdx(q->headIdx, q);

參考書籍:
1晴玖、《算法精解_C語言描述(中文版)》
2读存、《數(shù)據(jù)結(jié)構(gòu)與算法分析—C語言描述》

寫到這里箩艺,本文結(jié)束!下一篇宪萄,《數(shù)據(jù)結(jié)構(gòu):集合》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末艺谆,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子拜英,更是在濱河造成了極大的恐慌静汤,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件居凶,死亡現(xiàn)場離奇詭異虫给,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)侠碧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門抹估,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人弄兜,你說我怎么就攤上這事药蜻。” “怎么了替饿?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵语泽,是天一觀的道長。 經(jīng)常有香客問我视卢,道長踱卵,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任据过,我火速辦了婚禮惋砂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绳锅。我一直安慰自己西饵,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布榨呆。 她就那樣靜靜地躺著罗标,像睡著了一般。 火紅的嫁衣襯著肌膚如雪积蜻。 梳的紋絲不亂的頭發(fā)上闯割,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天,我揣著相機(jī)與錄音竿拆,去河邊找鬼宙拉。 笑死,一個(gè)胖子當(dāng)著我的面吹牛丙笋,可吹牛的內(nèi)容都是我干的谢澈。 我是一名探鬼主播煌贴,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼锥忿!你這毒婦竟也來了牛郑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤敬鬓,失蹤者是張志新(化名)和其女友劉穎淹朋,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钉答,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡础芍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了数尿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片仑性。...
    茶點(diǎn)故事閱讀 39,731評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖右蹦,靈堂內(nèi)的尸體忽然破棺而出诊杆,到底是詐尸還是另有隱情,我是刑警寧澤嫩实,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布刽辙,位于F島的核電站窥岩,受9級特大地震影響甲献,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜颂翼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一晃洒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧朦乏,春花似錦球及、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至刽锤,卻和暖如春镊尺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背并思。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工庐氮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人宋彼。 一個(gè)月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓弄砍,卻偏偏與公主長得像仙畦,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子音婶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評論 2 354

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