1. 程式人生 > >通過兩個佇列實現一個棧(C語言)

通過兩個佇列實現一個棧(C語言)

stackBy2Queue.h檔案

#pragma once

#define max_size 1000

typedef char DataType;

typedef struct Queue
{
    DataType data[max_size];
    int head;
    int tail;
    //佇列中有效元素個數
    int size;
}Queue;

typedef struct Stack
{
    Queue queue1;
    Queue queue2;
    //棧中有效元素個數
    int size;
}Stack;
//初始化函式
void
StackInit(Stack *stack); //銷燬函式 void StackDestroy(Stack *stack); //入棧操作函式 void StackPush(Stack *stack,DataType value); //出棧操作函式 void StackPop(Stack *stack); //取棧頂元素函式 int StackGetTop(Stack *stack,DataType *value);

stackBy2Queue.c檔案

#include<stdio.h>
#include"stackBy2Queue.h"

#define Test_Header printf("\n==========%s==========\n",__FUNCTION__);
//佇列初始化函式 void QueueInit(Queue *queue) { if(queue == NULL) { //非法輸入 return; } queue->head = 0; queue->tail = 0; queue->size = 0; } //佇列銷燬函式 void QueueDestroy(Queue *queue) { if(queue == NULL) { //非法輸入 return; } queue->head = 0
; queue->tail = 0; queue->size = 0; } //入佇列操作函式 void QueuePush(Queue *queue,DataType value) { if(queue == NULL) { //非法輸入 return; } if(queue->size >= max_size) { //佇列滿了 return; } queue->data[queue->tail++] = value; queue->size++; if(queue->tail > max_size) { //如果tail走到了佇列的尾部 queue->tail = 0; } } //出佇列操作函式 void QueuePop(Queue *queue) { if(queue == NULL) { //非法輸入 return; } if(queue->size == 0) { //空佇列 return; } if(queue->head >= max_size) { //如果head走到了佇列的最後一個元素 //呢出佇列以後繼續回到佇列一開始的地方 //就相當於是將最後一個元素出對佇列 queue->head = 0; } //否則直接將head往後移動一步 queue->head++; //將對列元素個數-1 queue->size--; if(queue->size == 0) { queue->head = 0; queue->tail = 0; } } //取隊首元素函式 int QueueGetTop(Queue *queue,DataType *value) { if(queue == NULL) { //非法輸入 return 0; } if(queue->size == 0) { //空佇列 return 0; } *value = queue->data[queue->head]; return 1; } void Print(Queue *queue) { if(queue == NULL) { //非法輸入 return; } if(queue->size == 0) { return; } if(queue->head < queue->tail) { int i = queue->head; for(;i < queue->tail;i++) { printf("%c ",queue->data[i]); } } else { int i = queue->head; while(queue->head < max_size) { printf("%c ",queue->data[queue->head]); queue->head++; } queue->head = 0; for(;i < queue->tail;i++) { printf("%c ",queue->data[i]); } } printf("\n\n"); }

以下為通過兩個佇列實現一個棧的入棧,出棧和取棧頂元素的操作

//棧初始化函式
void StackInit(Stack *stack)
{
    if(stack == NULL)
    {
        //非法輸入
        return;
    }
    QueueInit(&stack->queue1);
    QueueInit(&stack->queue2);
    stack->size = 0;
}
//棧銷燬函式
void StackDestroy(Stack *stack)
{
    if(stack == NULL)
    {
        //非法輸入
        return;
    }
    QueueDestroy(&stack->queue1);
    QueueDestroy(&stack->queue2);
    stack->size = 0;
}

入棧操作思路:
情況1:兩個佇列都為空那就隨便哪一個佇列將元素入佇列即可,也就相當於入棧操作,如下圖(虛線表示模擬一個棧)
這裡寫圖片描述
情況2:其中一個佇列有元素,一個佇列沒有元素,則將元素插入到有元素的佇列中,如下圖,此時待入棧的c和d要插入到佇列1中
這裡寫圖片描述

//入棧操作函式
void StackPush(Stack *stack,DataType value)
{
    if(stack == NULL)
    {
        //非法輸入
        return;
    }
    //每次入棧時找到佇列不為空的那一個佇列入佇列(相當於入棧)
    //或者兩個棧都為空時隨便入哪一個佇列都行
    if(stack->queue1.size != 0)
    {
        //佇列1不為空
        QueuePush(&stack->queue1,value);
    }
    else
    {
        //佇列2不為空或者兩個佇列都為空
       QueuePush(&stack->queue2,value);
    }
    //每入棧一個元素將棧的有效元素個數+1
    stack->size++;
}

出棧操作思路:如圖所示,此時佇列1 當中有元素
這裡寫圖片描述
但是由於佇列只能從隊首將元素出佇列,而我們入棧的元素順序是a b c d,所以根據棧後進先出的特點,此時出棧的元素應該是d,所以我們要將佇列1 中的元素移動到一個空佇列中也就是佇列2,但是我們必須留下佇列1中的隊尾的最後一個元素,只剩下最後一個元素時,將這個元素出佇列,就剛好模擬了棧的出棧操作。
這裡寫圖片描述

//出棧操作函式
void StackPop(Stack *stack)
{
    if(stack == NULL)
     {
         //非法輸入
         return;
     }
    if(stack->size == 0)
    {
        //空棧
        return;
    }
    Queue *from = NULL;
    Queue *to = NULL;
    //將from指向有元素的佇列,to指向沒有元素的佇列
    if(stack->queue1.size != 0)
    {
        from = &stack->queue1;
        to = &stack->queue2;
    }
    else
    {
        from = &stack->queue2;
        to = &stack->queue1;
    }
    //將from中的元素到騰到to中(但是from中必須要留下最後一個元素用於最後的出佇列也就是出棧操作)
    while(from->size != 1)
    {
        DataType top;
        //取到from佇列隊首元素的值
        QueueGetTop(from,&top);
        //然後對from佇列進行一次出棧操作
        QueuePop(from);
        //將從from佇列取到的隊首元素值插入到to佇列中
        QueuePush(to,top);
    }
    //迴圈結束
    //此時from中就剩下最後一個元素將其出佇列也就完成出棧操作
    QueuePop(from);
    //每出棧一次就將棧的有效元素個數-1
    stack->size--;
}

取棧頂元素思路:取棧頂元素操作和出棧操作類似,唯一不同的就是,當我們將元素移動到只剩下最後一個元素的時候,我們需要的是讀取到該元素的值(取隊首元素操作就行了),而這個元素依舊存在於該棧中,所以為了確保棧的元素不被破壞,讀取完元素值以後我們依舊要把該元素移動到另外那個佇列中去。

//取棧頂元素函式
int StackGetTop(Stack *stack,DataType *value)
{
    if(stack == NULL || value == NULL)
    {
        //非法輸入
        return 0;
    }
    if(stack->size == 0)
    {
        //空棧
        return 0;
    }
    Queue *from = NULL;
    Queue *to = NULL;
    //將from指向有元素的佇列,to指向沒有元素的佇列
    if(stack->queue1.size != 0)
    {
        from = &stack->queue1;
        to = &stack->queue2;
    }
    else
    {
        from = &stack->queue2;
        to = &stack->queue1;
    }
    //將from中的元素到騰到to中(但是from中必須要留下最後一個元素用於最後的取隊首元素操作也就是取棧頂元素操作)
    while(from->size != 1)
    {
        DataType top;
        //取到from佇列隊首元素的值
        QueueGetTop(from,&top);
        //然後對from佇列進行一次出棧操作
        QueuePop(from);
        //將從from佇列取到的隊首元素值插入到to佇列中
        QueuePush(to,top);
    }
    //迴圈結束
    //此時from中就剩下最後一個元素
    //對from佇列取隊首元素操作(也就是取棧頂元素)
    int ret = QueueGetTop(from,value);
    //當我們取到棧頂元素之後,在將該元素從from隊列出佇列
    QueuePop(from);
    //並且將該元素入to佇列
    //否則棧就被破壞了
    QueuePush(to,*value);
    return ret;
}
//列印函式便於觀察測試結果(思路不做解釋)
void PrintStackElem(Stack *stack,const char *msg)
{
    printf("[%s]\n",msg);
    if(stack == NULL)
    {
        //非法輸入
        return;
    }
    if(stack->size == 0)
    {
        //空棧
        return;
    }
    Queue *print = NULL;
    if(stack->queue1.size == 0)
    {
        print = &stack->queue2;
    }
    else
    {
        print = &stack->queue1;
    }
    Print(print);
}

//以下為測試函式
void TestStackBy2Queue()
{
    Test_Header;
    Stack stack;
    //初始化
    StackInit(&stack);
    //入棧函式測試
    StackPush(&stack,'a');
    StackPush(&stack,'b');
    StackPush(&stack,'c');
    StackPush(&stack,'d');
    PrintStackElem(&stack,"入棧4個元素expected:a b c d");
    //取棧頂元素測試
    DataType top;
    int ret = StackGetTop(&stack,&top);
    printf("expected ret = 1,actual ret = %d\n",ret);
    printf("expected top = d,actual top = %c\n",top);
    //出棧函式測試
    StackPop(&stack);
    StackPop(&stack);
    PrintStackElem(&stack,"出棧兩個元素之後expected: a b");
    //取棧頂元素函式測試2  
    ret = StackGetTop(&stack,&top);
    printf("expected ret = 1,actual ret = %d\n",ret);
    printf("expected top = b,actual top = %c\n",top);

    StackPop(&stack);
    StackPop(&stack);
    PrintStackElem(&stack,"將剩下的兩個元素出棧之後expected:");
    //取棧頂元素函式測試3
    ret = StackGetTop(&stack,&top);
    printf("expected ret = 0,actual ret = %d\n",ret);
    //銷燬棧
    StackDestroy(&stack);
}
//主函式呼叫測試函式
int main()
{
    TestStackBy2Queue();
    return 0;
}

測試結果如下圖:
這裡寫圖片描述