數據結構線性表之棧與隊列
1.棧
1.1.什麼是棧?
棧:一種特殊的線性表,其只允許在固定的一端進行插入和刪除元素操作。進行數據插入和刪除操作的一端稱爲棧頂,另一端稱爲棧底。棧中的數據元素遵守後進先出LIFO(Last
In First Out)的原則。
壓棧:棧的插入操作叫做進棧/壓棧/入棧,入數據在棧頂。
出棧:棧的刪除操作叫做出棧。出數據也在棧頂。
1.2.棧的實現
棧的實現一般可以使用數組或者鏈表實現,相對而言數組的結構實現更優一些。因爲數組在尾上插入數據的代價比較小。
棧一般可以分爲:
1.靜態棧:使用定長數組存儲
typedef int STDataType;
#define N 10
typedef struct Stack
{
STDataType a[N];
int top; // 棧頂
}Stack;
2.動態棧:使用動態開闢的數組存儲
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top; // 棧頂
int capacity; // 容量
}Stack;
1.3.棧的實現(github鏈接):
棧的實現
1.4.棧的OJ習題
給定一個只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判斷字符串是否有效。OJ鏈接
思路分析:利用棧的後進先出原理。遍歷字符串,當輸入爲" ({[ " 時,入棧;當輸入爲 “]})” 和棧頂元素匹配則出棧,直到遍歷字符串結束,若棧最終爲空則返回 true;如果不匹配則直接結束。
具體代碼如下:
//由於C語言庫中沒有棧,故此處需要棧的實現代碼
bool isValid(char * s){
Stack st;
StackInit(&st);
while(*s)
{
if(*s == '[' || *s == '(' || *s == '{')
{
StackPush(&st, *s);
++s;
}
else
{
if(StackEmpty(&st) == 1)
return false;
char top = StackTop(&st);
StackPop(&st);
if(*s == ']' && top == '[')
{
++s;
continue;
}
else if(*s == ')' && top == '(')
{
++s;
continue;
}
else if(*s == '}' && top == '{')
{
++s;
continue;
}
else
{
return false;
}
}
}
bool ret = StackEmpty(&st) == 1;
StackDestory(&st);
return ret;
2.隊列
2.1.什麼是隊列?
隊列:一種特殊的線性表,只允許在一端進行插入數據操作,在另一端進行刪除數據操作的特殊線性表。隊列具有先進先出FIFO(First In First Out)的特點。
入隊列:進行插入操作的一端稱爲隊尾
出隊列:進行刪除操作的一端稱爲隊頭
2.2.隊列的實現
隊列也可以用數組或者鏈表的結構實現,使用鏈表的結構實現更優,因爲使用數組的結構,出隊列在數組頭上出數據,效率會降低。
隊列的創建
// 鏈式結構
typedef struct QListNode
{
struct QListNode* pNext;
QDataType data;
}QNode;
// 隊列的結構
typedef struct Queue
{
QNode* front;
QNode* rear;
}Queue;
2.3.隊列的實現(github鏈接):
隊列的實現
2.4.循環隊列
實際中我們還會使用一種隊列叫循環隊列。如操作系統中的生產者、消費者模型。環形隊列可以使用數組(取模)實現,也可以使用循環鏈表實現。
2.4.1.判斷隊空與隊滿
隊空:Q.rear = Q.front
隊滿:Q.rear + 1 = Q.front
2.4.2.實現循環隊列
設計你的循環隊列實現。 循環隊列是一種線性數據結構,其操作表現基於 FIFO(先進先出)原則並且隊尾被連接在隊首之後以形成一個循環。OJ鏈接
具體代碼如下:
typedef struct {
int* _a;
int _n;
int _front;
int _rear;
} MyCircularQueue;
bool myCircularQueueIsFull(MyCircularQueue* obj);
bool myCircularQueueIsEmpty(MyCircularQueue* obj);
/** Initialize your data structure here.
Set the size of the queue to be k. */
MyCircularQueue* myCircularQueueCreate(int k)
{
MyCircularQueue* cq = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
cq->_a = (int*)malloc(sizeof(int)*(k + 1));
cq->_n = k + 1; cq->_front = cq->_rear = 0;
return cq;
}
/** Insert an element into the circular queue.
Return true if the operation is successful. */
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(myCircularQueueIsFull(obj))
return false;
obj->_a[obj->_rear] = value;
obj->_rear++;
if(obj->_rear == obj->_n)
obj->_rear = 0;
return true;
}
/** Delete an element from the circular queue.
Return true if the operation is successful. */
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return false;
++obj->_front;
if(obj->_front == obj->_n)
obj->_front = 0;
return true;
}
/** Get the front item from the queue. */
int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
return obj->_a[obj->_front];
}
/** Get the last item from the queue. */
int myCircularQueueRear(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
int prevRear = obj->_rear - 1;
if (obj->_rear == 0)
prevRear = obj->_n - 1;
return obj->_a[prevRear];
}
/** Checks whether the circular queue is empty or not. */
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->_front == obj->_rear;
}
/** Checks whether the circular queue is full or not. */
bool myCircularQueueIsFull(MyCircularQueue* obj) {
int nextRear = obj->_rear + 1;
nextRear %= obj->_n;
return nextRear == obj->_front;
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->_a);
free(obj);
}
2.5.隊列的OJ習題
1.用隊列實現棧。OJ鏈接
思路分析:用兩個隊列q1和q2,總是保持一個隊列爲空。
1.入棧時向非空的一個隊列push;
2.出棧時,設q1非NULL,則從q1隊頭取元素入隊到q2中,直到q1中剩下一個元素,這個元素即爲棧頂元素。
3.求top直接返回非空隊列的隊尾即可。
2.用棧實現隊列。OJ鏈接
思路分析:
入隊:把 pushst中所有的元素移到 popst 中,接着把新元素壓入 pushst。再把 pushst中的元素移到 popst 中,最後把popst中所有的元素彈出。
出隊:直接從 popst 彈出就可以了,因爲popst 的棧頂元素就是隊列的隊首元素。
OJ代碼(github鏈接)
OJ代碼實現