C++ STL 之 stack 和 queue

本節(jié)我們將介紹 STL 中的 stack 和 queue 容器使用逆日。



棧和隊(duì)列都是極其重要的數(shù)據(jù)結(jié)構(gòu),C++ STL 中也提供了 stack 和 queue 等容器萄凤。它們的概念理解起來不難室抽,使用起來也十分方便,接下來我們將一一介紹這些容器蛙卤,并結(jié)合一些相關(guān)的例題來加深理解狠半。

stack 容器

stack<T> 容器適配器中的數(shù)據(jù)是以 LIFO 的方式組織的,即先進(jìn)后出颤难,當(dāng)想訪問棧內(nèi)某一元素時(shí)神年,必須將其頂部的元素都彈出出棧后,才能訪問該元素行嗤。
下圖演示了 stack 容器的一些基本操作已日。

stack 容器

棧(stack) 有著廣泛的應(yīng)用。例如我們?cè)诤芏嘬浖惺褂玫某蜂N操作(ctrl + z)栅屏,信心觀察會(huì)發(fā)現(xiàn)飘千,不同軟件中撤銷操作回撤的數(shù)據(jù)量是不同的堂鲜,這也許和棧的不同有關(guān)吧。還有算術(shù)表達(dá)式的求值等等护奈,都會(huì)用到棧這種數(shù)據(jù)結(jié)構(gòu)缔莲。

stack 的定義

定義一個(gè)存放字符串棧:

stack<string> data;

stack 容器適配器的模板有兩個(gè)參數(shù):
第一個(gè)參數(shù)是存儲(chǔ)對(duì)象的類型。
第二個(gè)參數(shù)是底層容器的類型霉旗。
stack<T> 的底層容器默認(rèn)是 deque<T> 容器痴奏,因此模板類型其實(shí)是

stack<typename T, typename Container = deque<T>>

通過指定第二個(gè)模板類型參數(shù),可以使用任意類型的底層容器厌秒,只要它們支持 back()读拆,push_back(),pop_back()鸵闪。

下面展示了如何定義一個(gè)使用了 list<T> 的堆棧:

stack<int,list<int>> data;

在創(chuàng)建堆棧時(shí)檐晕,不能在初始化列表中初始化,但是可以用另一個(gè)容器來初始化蚌讼,只要堆棧的底層容器類型和這個(gè)容器的類型是相同的辟灰。

list<int> data_ {0,1,2,3};
stack<int,list<int>> data(data_);

第二條語句生成了一個(gè)包含 data_ 元素副本的 data 。
這里不能在 stack 構(gòu)造函數(shù)中使用初始化列表啦逆,必須使用圓括號(hào)伞矩。如果沒有在第二個(gè) stack 模板類型參數(shù)中將底層容器指定為 list,那么底層容器可能是 deque夏志,這樣就不能用 list 的內(nèi)容來初始化 stack乃坤,而只能接受 deque。

stack<T> 模板定義了拷貝構(gòu)造函數(shù)沟蔑,因而可以復(fù)制現(xiàn)有的 stack 容器:

stack<int,list<double>> copy_data {data};

copy_data 是 data 的副本湿诊。
在使用拷貝構(gòu)造函數(shù)時(shí),既可以用初始化列表瘦材,也可以用圓括號(hào)厅须。
而在 stack 構(gòu)造函數(shù)中必須使用圓括號(hào)。

stack的相關(guān)操作

和之前介紹的容器相比食棕,stack 是一類存儲(chǔ)機(jī)制簡單朗和、所提供操作較少的容器。
下面是 stack 容器可以提供的一套完整操作:

函數(shù) 功能
top() 返回棧頂元素的引用簿晓,類型為 T&眶拉,如果棧為空,返回值未定義
pop() 棧頂元素出棧
size() 返回棧中元素的個(gè)數(shù)
empty() 棧中沒有元素時(shí)返回 true
emplace() 使用傳入的參數(shù)調(diào)用構(gòu)造函數(shù)憔儿,在棧頂生成對(duì)象
push(const T& obj) 將對(duì)象副本壓入棧頂忆植,通過調(diào)用底層容器的 push_back() 函數(shù)實(shí)現(xiàn)
push(T&& obj) 以移動(dòng)對(duì)象的方式將對(duì)象壓入棧,通過調(diào)用底層容器的有右值引用參數(shù)的 push_back() 函數(shù)實(shí)現(xiàn)
swap(stack<T> & other_stack) 將當(dāng)前棧中的元素和參數(shù)中的元素交換,參數(shù)所包含元素的類型必須和當(dāng)前棧的相同朝刊,對(duì)于 stack 對(duì)象有一個(gè)特例化的全局函數(shù) swap() 可以使用

stack 的訪問:

deque<int> data_ {0,1,2,3,4};
//初始化一個(gè)棧
stack<int> data(data_);
cout<<"data : "<<data.size()<<endl;
while(!data.empty()){
       //獲得棧頂元素
   cout<<data.top()<<" ";
       //棧頂元素出棧
   data.pop();
   }
cout<<endl;
cout<<"data : "<<data.size()<<endl;

打印的結(jié)果為:

data : 5
4 3 2 1 0
data : 0

stack<T> 模板也定義了復(fù)制和移動(dòng)版的 operator=() 函數(shù)耀里,因此可以將一個(gè) stack 對(duì)象賦值給另一個(gè) stack 對(duì)象。stack 對(duì)象有一整套比較運(yùn)算符拾氓。比較運(yùn)算通過字典的方式來比較底層容器中相應(yīng)的元素冯挎。字典比較是一種用來對(duì)字典中的單詞進(jìn)行排序的方式。依次比較對(duì)應(yīng)元素的值痪枫,直到遇到兩個(gè)不相等的元素织堂。第一個(gè)不匹配的元素會(huì)作為字典比較的結(jié)果。如果一個(gè) stack 的元素比另一個(gè) stack 的多奶陈,但是所匹配的元素都相等,那么元素多的那個(gè) stack 容器大于元素少的 stack 容器附较。

queue 容器

queue<T> 是一種只能訪問第一個(gè)和最后一個(gè)元素的容器適配器吃粒,只能在容器的末尾添加新元素,只能從頭部移除元素拒课。

許多程序都使用了 queue 容器徐勃,如生活中的排隊(duì)隊(duì)列,對(duì)于任何需要用 FIFO 準(zhǔn)則處理的序列來說早像,使用 queue 容器適配器都是好的選擇僻肖。

下圖展示了一個(gè) queue 容器及其一些基本操作

queue 容器

queue 的定義

queue 的生成方法和 stack 相同。
創(chuàng)建一個(gè)保存整形數(shù)據(jù)的隊(duì)列:

queue<int> data;

使用 list 創(chuàng)建隊(duì)列:

list<int> data_{0,1,2,3};
queue<int,list<int>> q(data_);

使用拷貝構(gòu)造函數(shù):

list<int> data_{0,1,2,3};
queue<int,list<int>> q(data_);
queue<int,list<int>> copy_q {q};

或者:

deque<int> data_{1,2,3,0,4};
queue<int> q (data_);

stack<T>卢鹦、queue<T> 這類適配器類都默認(rèn)封裝了一個(gè) deque<T> 容器臀脏,也可以通過指定第二個(gè)模板類型參數(shù)來使用其他類型的容器:

queue<int,list<int>> data;

底層容器必須提供這些操作:front(),back()冀自,push_back()揉稚,pop_front(),empty() 和 size()熬粗。

queuu 操作

queue 和 stack 有一些成員函數(shù)相似搀玖,但某些情況下,功能有些不同:

函數(shù) 功能
front() 返回 queue 中第一個(gè)元素的引用驻呐。如果 queue 是常量灌诅,就返回一個(gè)常引用;如果 queue 為空含末,返回值是未定義的
back() 返回 queue 中最后一個(gè)元素的引用猜拾。如果 queue 是常量,就返回一個(gè)常引用答渔;如果 queue 為空关带,返回值是未定義的
push(const T& obj) 在 queue 的尾部添加一個(gè)元素的副本。通過調(diào)用底層容器的成員函數(shù) push_back() 實(shí)現(xiàn)
push(T&& obj) 以移動(dòng)的方式在 queue 的尾部添加元素。通過調(diào)用底層容器的具有右值引用參數(shù)的成員函數(shù) push_back() 實(shí)現(xiàn)
pop() 刪除 queue 中的第一個(gè)元素(頭部元素)
size() 返回 queue 中元素的個(gè)數(shù)
empty() 如果 queue 中沒有元素宋雏,返回 true
emplace() 使用 emplace() 中的參數(shù)調(diào)用 T 的構(gòu)造函數(shù)芜飘,在 queue 的尾部生成對(duì)象
swap(queue<T> &other_q) 將當(dāng)前 queue 中的元素和參數(shù) queue 中的元素交換。包含元素的類型相同磨总。也可以調(diào)用全局函數(shù)模板 swap() 來完成同樣的操作

和 stack 一樣嗦明,queue 也沒有迭代器。訪問元素的唯一方式是遍歷容器內(nèi)容蚪燕,并移除訪問過的每一個(gè)元素娶牌。例如:

deque<int> data_ {0,1,2,3,4};
queue<int> data(data_);
cout<<"data : "<<data.size()<<endl;
while(!data.empty()){
    cout<<data.front()<<" ";
    data.pop();
    }
cout<<endl;
cout<<"data : "<<data.size()<<endl;

打印的內(nèi)容為:

data : 5
0 1 2 3 4
data : 0

用循環(huán)打印 data 的全部內(nèi)容,循環(huán)由 empty() 返回的值控制馆纳。調(diào)用 empty() 可以保證我們能夠調(diào)用一個(gè)空隊(duì)列的 front() 函數(shù)诗良。
如上所示,為了訪問 queue 中的全部元素鲁驶,必須刪除它們鉴裹。如果不想刪除容器中的元素,必須將它們復(fù)制到另一個(gè)容器中钥弯。如果一定要這么操作径荔,我們可能需要換一個(gè)容器。

queue<T> 模板定義了拷貝和移動(dòng)版的 operator=()脆霎,對(duì)于所保存元素類型相同的 queue 對(duì)象总处,它們有一整套的比較運(yùn)算符,這些運(yùn)算符的工作方式和 stack 容器相同睛蛛。

典例

這里列舉兩個(gè)來自 LeetCode 的題鹦马。

用隊(duì)列實(shí)現(xiàn)棧

使用隊(duì)列實(shí)現(xiàn)棧的下列操作:

    push(x) -- 元素 x 入棧
    pop() -- 移除棧頂元素
    top() -- 獲取棧頂元素
    empty() -- 返回棧是否為空

注意:
你只能使用隊(duì)列的基本操作-- 也就是 push to back, peek/pop from front, size, 和 is empty 這些操作是合法的。
你所使用的語言也許不支持隊(duì)列玖院。 你可以使用 list 或者 deque(雙端隊(duì)列)來模擬一個(gè)隊(duì)列 , 只要是標(biāo)準(zhǔn)的隊(duì)列操作即可菠红。
你可以假設(shè)所有操作都是有效的(例如, 對(duì)一個(gè)空的棧不會(huì)調(diào)用 pop 或者 top 操作)。

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/implement-stack-using-queues

代碼模板:

class MyStack {
public:
    /** Initialize your data structure here. */
    MyStack() {
        
    }
    
    /** Push element x onto stack. */
    void push(int x) {
        
    }
    
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        
    }
    
    /** Get the top element. */
    int top() {
        
    }
    
    /** Returns whether the stack is empty. */
    bool empty() {
        
    }
};

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack* obj = new MyStack();
 * obj->push(x);
 * int param_2 = obj->pop();
 * int param_3 = obj->top();
 * bool param_4 = obj->empty();
 */

該題要求使用隊(duì)列實(shí)現(xiàn)棧难菌,即我們需要用隊(duì)列的函數(shù)來實(shí)現(xiàn)棧的函數(shù)围段,棧是在棧頂入棧元素和出棧元素精盅,隊(duì)列是只能在尾部增加元素,在隊(duì)頭刪除元素,因此可以將隊(duì)列頭部作為棧頂初橘,尾部作為棧底勾习。
首先轧坎,我們得建立一個(gè)隊(duì)列作為成員函數(shù)股耽。

queue<int> nums;

先從最簡單的 empty() 函數(shù)開始,返回棧是否為空褐健,顯然:

return nums.empty();

之后考慮 top() 函數(shù)付鹿,棧的 top() 函數(shù)是獲取棧頂元素澜汤,那么我們只需要返回隊(duì)列第一個(gè)元素即可。

return nums.front();

再考慮 pop() 函數(shù)舵匾,移除棧頂元素俊抵,返回隊(duì)頭元素,并彈出坐梯。

int num=nums.front();
nums.pop();
return num;

最后考慮 push(int x) 徽诲,元素 x 入棧。

隊(duì)列是只能在尾部增加元素吵血,在隊(duì)頭刪除元素谎替,之前提到過,我們將隊(duì)列頭部的刪除元素功能當(dāng)作出棧功能蹋辅,同時(shí)棧頂也有入棧功能钱贯。
為此,當(dāng)在隊(duì)列尾部增加元素后晕翠,該元素在隊(duì)列尾喷舀,對(duì)應(yīng)棧,該元素卻在棧底淋肾,不在棧頂。
因此爸邢,在進(jìn)入隊(duì)列時(shí)樊卓,需要將隊(duì)列其他元素出隊(duì)列,然后入隊(duì)列杠河,這樣新加入的元素才能在隊(duì)列頭部碌尔,相當(dāng)于棧頂。

nums.push(x);
for(int i=1;i<nums.size();i++){
     int num=nums.front();
     nums.push(num);
     nums.pop();
}

完整代碼如下:

class MyStack {
public:
    queue<int> nums;
    /** Initialize your data structure here. */
    MyStack() {
        
    }
    
    /** Push element x onto stack. */
    void push(int x) {
        nums.push(x);
        for(int i=1;i<nums.size();i++){
            int num=nums.front();
            nums.push(num);
            nums.pop();
        }
    }
    
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        int num=nums.front();
        nums.pop();
        return num;
    }
    
    /** Get the top element. */
    int top() {
        return nums.front();
    }
    
    /** Returns whether the stack is empty. */
    bool empty() {
        return nums.empty();
    }
};

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack* obj = new MyStack();
 * obj->push(x);
 * int param_2 = obj->pop();
 * int param_3 = obj->top();
 * bool param_4 = obj->empty();
 */

這樣券敌,我們就實(shí)現(xiàn)了用隊(duì)列實(shí)現(xiàn)棧了唾戚。

用棧實(shí)現(xiàn)隊(duì)列

使用棧實(shí)現(xiàn)隊(duì)列的下列操作:

    push(x) -- 將一個(gè)元素放入隊(duì)列的尾部。
    pop() -- 從隊(duì)列首部移除元素待诅。
    peek() -- 返回隊(duì)列首部的元素叹坦。
    empty() -- 返回隊(duì)列是否為空。

示例:

MyQueue queue = new MyQueue();

queue.push(1);
queue.push(2);  
queue.peek();  // 返回 1
queue.pop();   // 返回 1
queue.empty(); // 返回 false

說明:
你只能使用標(biāo)準(zhǔn)的棧操作 -- 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的卑雁。
你所使用的語言也許不支持棧募书。你可以使用 list 或者 deque(雙端隊(duì)列)來模擬一個(gè)棧,只要是標(biāo)準(zhǔn)的棧操作即可测蹲。
假設(shè)所有操作都是有效的 (例如莹捡,一個(gè)空的隊(duì)列不會(huì)調(diào)用 pop 或者 peek 操作)。

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/implement-queue-using-stacks

代碼模板:

class MyQueue {
public:
    /** Initialize your data structure here. */
    MyQueue() {
        
    }
    
    /** Push element x to the back of queue. */
    void push(int x) {
        
    }
    
    /** Removes the element from in front of queue and returns that element. */
    int pop() {
        
    }
    
    /** Get the front element. */
    int peek() {
        
    }
    
    /** Returns whether the queue is empty. */
    bool empty() {
        
    }
};

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue* obj = new MyQueue();
 * obj->push(x);
 * int param_2 = obj->pop();
 * int param_3 = obj->peek();
 * bool param_4 = obj->empty();
 */

類似的扣甲,我們需要用棧的函數(shù)來實(shí)現(xiàn)隊(duì)列的函數(shù)篮赢。
棧是只能在棧頂入元素和彈出元素的,而隊(duì)列是在頭部彈出元素,尾部增加元素的启泣。
顯然涣脚,一個(gè)棧是不夠用的,我們需要兩個(gè)棧种远,用一個(gè)主棧 data1 和一個(gè)輔助棧 data2 存儲(chǔ)數(shù)據(jù)涩澡。
data1 是主棧,其棧底當(dāng)作隊(duì)列的頭部坠敷,其棧頂當(dāng)作隊(duì)列的尾部妙同。
data2 輔助完成隊(duì)列的 peek(),pop() 和 push(int x) 功能膝迎。

首先粥帚,我們建立兩個(gè)棧作為類成員。

stack<int> data1;
stack<int> data2;

先從 empty() 函數(shù)出發(fā)限次,返回隊(duì)列是否為空芒涡,顯然:

return data1.empty() && data2.empty();

之后考慮 peek() 函數(shù),返回隊(duì)列首部的元素卖漫。
data1 是主棧费尽,需要獲得其棧底元素,當(dāng)作隊(duì)列的首部元素羊始。
我們可以先將 data1 的所有元素出棧旱幼,入棧至 data2 中,此時(shí) data2 的棧頂為隊(duì)列首部元素突委。

while(!data1.empty()){
    int num = data1.top();
    data2.push(num);
    data1.pop();
}
return data2.top();

然后 pop() 函數(shù)柏卤,從隊(duì)列首部移除元素,和 peek() 類似匀油,只要使 data2 的棧頂元素出棧即可缘缚。

while(!data1.empty()){
    int num = data1.top();
    data2.push(num);
    data1.pop();
}
int num_ = data2.top();
data2.pop();
return num_; 

最后,push(int x) 函數(shù)敌蚜,將一個(gè)元素放入隊(duì)列的尾部桥滨。
我們知道 data1 的棧頂使當(dāng)作隊(duì)列的尾部,而在之前的 pop() 和 peek() 中钝侠,數(shù)據(jù)都保存在 data2 中的该园,因此我們先將 data2 中的數(shù)據(jù)出棧并入棧到 data1 中,然后將 x 入棧至 data1 中即可帅韧。

while(!data2.empty()){
    int num = data2.top();
    data1.push(num);
    data2.pop();
}
data1.push(x);

完整代碼如下:

class MyQueue {
public:
    stack<int> data1;
    stack<int> data2;
    /** Initialize your data structure here. */
    MyQueue() {
        
    }
    
    /** Push element x to the back of queue. */
    void push(int x) {
        while(!data2.empty()){
            int num = data2.top();
            data1.push(num);
            data2.pop();
        }
        data1.push(x);
    }
    
    /** Removes the element from in front of queue and returns that element. */
    int pop() {
        while(!data1.empty()){
            int num = data1.top();
            data2.push(num);
            data1.pop();
        }
        int num_ = data2.top();
        data2.pop();
        return num_; 
    }
    
    /** Get the front element. */
    int peek() {
        while(!data1.empty()){
            int num = data1.top();
            data2.push(num);
            data1.pop();
        }
        return data2.top();
    }
    
    /** Returns whether the queue is empty. */
    bool empty() {
        return data1.empty() && data2.empty();
    }
};

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue* obj = new MyQueue();
 * obj->push(x);
 * int param_2 = obj->pop();
 * int param_3 = obj->peek();
 * bool param_4 = obj->empty();
 */

這樣里初,我們就實(shí)現(xiàn)了用棧實(shí)現(xiàn)隊(duì)列了。



這兩個(gè)題雖然簡單忽舟,但是幫助我們對(duì)棧和隊(duì)列的理解是大有裨益的双妨,棧和隊(duì)列還有著很重要的應(yīng)用淮阐,多多做題無疑是熟練使用它們的一個(gè)很好手段。

至此刁品,stack 和 queue 容器的介紹就暫告一段落了泣特。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市挑随,隨后出現(xiàn)的幾起案子状您,更是在濱河造成了極大的恐慌,老刑警劉巖兜挨,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件膏孟,死亡現(xiàn)場離奇詭異,居然都是意外死亡拌汇,警方通過查閱死者的電腦和手機(jī)柒桑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來噪舀,“玉大人魁淳,你說我怎么就攤上這事∮氤” “怎么了界逛?”我有些...
    開封第一講書人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長纺座。 經(jīng)常有香客問我仇奶,道長,這世上最難降的妖魔是什么比驻? 我笑而不...
    開封第一講書人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮岛抄,結(jié)果婚禮上别惦,老公的妹妹穿的比我還像新娘。我一直安慰自己夫椭,他們只是感情好掸掸,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蹭秋,像睡著了一般扰付。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上仁讨,一...
    開封第一講書人閱讀 51,598評(píng)論 1 305
  • 那天羽莺,我揣著相機(jī)與錄音,去河邊找鬼洞豁。 笑死盐固,一個(gè)胖子當(dāng)著我的面吹牛荒给,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播刁卜,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼志电,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了蛔趴?” 一聲冷哼從身側(cè)響起挑辆,我...
    開封第一講書人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎孝情,沒想到半個(gè)月后鱼蝉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡咧叭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年蚀乔,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片菲茬。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡吉挣,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出婉弹,到底是詐尸還是另有隱情睬魂,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布镀赌,位于F島的核電站氯哮,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏商佛。R本人自食惡果不足惜喉钢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望良姆。 院中可真熱鬧肠虽,春花似錦、人聲如沸玛追。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽痊剖。三九已至韩玩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間陆馁,已是汗流浹背找颓。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留氮惯,地道東北人叮雳。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓想暗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親帘不。 傳聞我的和親對(duì)象是個(gè)殘疾皇子说莫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

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