數據結構刷題訓練:隊列實現棧

目錄

前言

1. 題目:使用隊列實現棧

2. 思路

3. 分析?

3.1 創建棧

3.2入棧

3.3 出棧

3.4 棧頂數據

3.5 判空和 “ 棧 ” 的銷毀

?4. 題解

總結


前言

????????我們已經學習了棧和隊列,也都實現了它們各自的底層接口,那么接下我們就要開始棧和隊列的專項刷題訓練。


1. 題目:使用隊列實現棧

題目描述:

?題目鏈接:

隊列實現棧icon-default.png?t=N6B9https://leetcode.cn/problems/implement-stack-using-queues/

?2. 思路

????????隊列的結構是先進先出,題目的要求是,讓我們利用隊列的底層接口來實現棧,不可以改變隊列的底層邏輯,所以如果你的思路是逆置隊列這個鏈表,那這個思路就被pass掉了。

? ? ? ? ?那我們要如何利用隊列尾進頭出的特性來實現棧的尾進尾出呢?題目中給了我們兩個隊列,我們要使用這兩個隊列實現棧。

? ? ? ? 入棧操作好說,問題在于出棧問題,思路是這樣的:我們有兩個隊列,一個隊列用于存儲數據,另外一個隊列(空隊列)用于拷貝數據,將原隊列的前n-1個數據拷貝到空隊列中,然后再將原隊列剩余的最后一個元素出隊列,這樣就模擬實現了棧的尾出


?

3. 分析?

?????????根據上述的思路分析,隊列實現棧,入棧不需要什么特殊操作例如我們入棧:1、2、3、4、5,出棧呢就是:5、4、3、2、1。

????????上述的思路已經介紹了解決辦法,也是非常簡單的,但有人可能會問:那這樣算法的效率豈不是很低?這種方法的效率確實低,但是這道題目考察的并不是效率的問題,而實性質問題,這也是一道經典的面試題目。這道題目并不難,但它考察對數據結構的理解,各各接口的實現中有很多需要注意的細節。

????????首先這道題目是并沒有給現成的隊列,使用C語言解決需要我們現成造輪子,這也是C語言刷題的弊端,有很多題目都需要造輪子。那么這里我們就可以直接復制前邊我們實現的隊列。

?接下來就是我們開始注意實現接口:

?????????首先題目中給了我們兩個隊列,為了便于傳參和使用,我們可以定義一個結構體:

typedef struct {
Que q1;    //注意這里定于的隊列類型一定要與自己定義的隊列結構體類型對應
Que q2;
} MyStack;

?這里我們在前邊介紹結構體時提到過,匿名結構體。

?3.1 創建棧

MyStack* myStackCreate() {}

?題目給出的接口如上,那這里我們要怎么創建我們的棧呢?是這樣嗎?

MyStack* myStackCreate() {MyStack st;//…return &st;
}

?????????對函數和指針比較熟悉的同學可能就已經發現不行,為什么不行?這里就牽扯到了函數相關的知識,函數內創建的變量都是存儲在棧區,出了函數就會被銷毀,內存已經被銷毀,返回指針還有什么意義呢?所以這里需要使用malloc函數,動態內存分配開辟的空間在堆區,程序結束前不主動釋放就一直存在。所以上述的創建變量的方法不可取。

正確的方法:

MyStack* myStackCreate() {MyStack* pst=(MyStack*)malloc(sizeof(MyStack));QueueInit(&pst->q1);QueueInit(&pst->q2);return pst;
}

?????????這里的pst->q1,就等價于我們在創建的隊列的結構體變量:Que q;在調用接口時需要傳地址過去。

3.2入棧

????????接下來就是入棧,題目中給了我們兩個隊列,為了后續出棧操作我們需要確保一個隊列為空,用于拷貝數據,所以我們入棧時需要在不為空的隊列入。

void myStackPush(MyStack* obj, int x) {if(!IsEmpty(&obj->q1)){QueuePush(&obj->q1,x);}else{QueuePush(&obj->q2,x);}
}

如果兩個都為空那就隨便選一個都可以。

3.3 出棧

????????在進行出棧操作的時候,我們需要判斷哪一個隊列為空,然后將非空隊列的前n-1個元素依次拷貝到空隊列當中。這里我們可以先假設隊列1為空,然后在判斷隊列1是否為空,如果不為空那就是隊列2為空,進行修改。這個假設的方法還是很實用的。

?拷貝過程如下:

????????注意這里是拷貝,不是將原隊列的節點插入到空隊列,而是通過隊頭數據這個函數接口來將數據傳過去,然后入隊(調用入隊接口),入隊之后及時更新隊頭(出隊)。

?

?

int myStackPop(MyStack* obj) {Que* Empty=&obj->q1;Que* NoEmpty=&obj->q2;if(!IsEmpty(&obj->q1)){Empty=&obj->q2;NoEmpty=&obj->q1;}while(QueueSize(NoEmpty)>1){QueuePush(Empty,QueueFront(NoEmpty));QueuePop(NoEmpty);}int top=QueueFront(NoEmpty);//最后保存非空隊列最后一個隊列節點的數據,便于返回QueuePop(NoEmpty);          //最后一個元素出隊。return top;
}

?3.4 棧頂數據

?????????棧頂數據接口實現就簡單了,我們前邊對隊列進行實現時,有隊頭和隊尾數據的接口,我們可以直接調用。

int myStackTop(MyStack* obj) {if(!IsEmpty(&obj->q1)){return QueueBlack(&obj->q1);}else{return QueueBlack(&obj->q2);}
}

?3.5 判空和 “ 棧 ” 的銷毀

?????????判空就很簡單,如果兩個隊列都為空,那么這個 “ 棧 ” 也就為空。

bool myStackEmpty(MyStack* obj) {return (IsEmpty(&obj->q1)&&IsEmpty(&obj->q2));
}

?????????“ 棧 ”的銷毀,這里就不能直接free掉obj了,如果直接釋放那我們程序中的兩個隊列就會丟失無法釋放,所以在釋放掉obj之前,我們需要先將兩個隊列銷毀。

void myStackFree(MyStack* obj) {DestoryQueue(&obj->q1);DestoryQueue(&obj->q2);free(obj);
}

?4. 題解

?完整代碼如下:

typedef int Datatype;
typedef struct QueueNode
{struct QueueNode* next;Datatype data;}QueueNode;
typedef struct Queue
{QueueNode* head;QueueNode* tail;int size;
}Que;
//初始化隊列
void QueueInit(Que* pq);
//入隊
void QueuePush(Que* pq, Datatype x);
//出隊
void QueuePop(Que* pq);
//隊頭數據
Datatype QueueFront(Que* pq);
//隊尾數據
Datatype QueueBlack(Que* pq);
//判空
bool IsEmpty(Que* pq);
//隊列大小
int QueueSize(Que* pq);
//銷毀隊列
void DestoryQueue(Que* pq);void QueueInit(Que* pq)
{assert(pq);pq->head = pq->tail = NULL;pq->size = 0;
}
void QueuePush(Que* pq, Datatype x)
{assert(pq);QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));if (newnode == NULL){perror("malloc");exit(-1);}newnode->data = x;newnode->next = NULL;if (pq->tail == NULL){pq->head = pq->tail = newnode;}else{pq->tail->next = newnode;pq->tail = newnode;}pq->size++;
}
void QueuePop(Que* pq)
{assert(pq);assert(!IsEmpty(pq));if (pq->head->next == NULL){free(pq->head);pq->head = pq->tail = NULL;}else{QueueNode* next = pq->head->next;free(pq->head);pq->head = next;}pq->size--;
}
Datatype QueueFront(Que* pq)
{assert(pq);assert(!IsEmpty(pq));return pq->head->data;
}
Datatype QueueBlack(Que* pq)
{assert(pq);assert(!IsEmpty(pq));return pq->tail->data;
}
bool IsEmpty(Que* pq)
{assert(pq);return (pq->head == NULL);
}
int QueueSize(Que* pq)
{assert(pq);return pq->size;
}
void DestoryQueue(Que* pq)
{assert(pq);QueueNode* cur = pq->head;while (cur){QueueNode* next = cur->next;free(cur);cur = next;}pq->head = pq->tail = NULL;pq->size = 0;
}
typedef struct {
Que q1;
Que q2;
} MyStack;MyStack* myStackCreate() {MyStack* pst=(MyStack*)malloc(sizeof(MyStack));QueueInit(&pst->q1);QueueInit(&pst->q2);return pst;
}void myStackPush(MyStack* obj, int x) {if(!IsEmpty(&obj->q1)){QueuePush(&obj->q1,x);}else{QueuePush(&obj->q2,x);}
}int myStackPop(MyStack* obj) {Que* Empty=&obj->q1;Que* NoEmpty=&obj->q2;if(!IsEmpty(&obj->q1)){Empty=&obj->q2;NoEmpty=&obj->q1;}while(QueueSize(NoEmpty)>1){QueuePush(Empty,QueueFront(NoEmpty));QueuePop(NoEmpty);}int top=QueueFront(NoEmpty);QueuePop(NoEmpty);return top;
}int myStackTop(MyStack* obj) {if(!IsEmpty(&obj->q1)){return QueueBlack(&obj->q1);}else{return QueueBlack(&obj->q2);}
}bool myStackEmpty(MyStack* obj) {return (IsEmpty(&obj->q1)&&IsEmpty(&obj->q2));
}void myStackFree(MyStack* obj) {DestoryQueue(&obj->q1);DestoryQueue(&obj->q2);free(obj);
}

?

總結

? ? ? ? 本文隊列模擬實現棧,讓我們在實踐中深入思考了數據結構的本質和應用,為我們的編程能力和問題解決能力提供了鍛煉。本期內容到此結束,感謝閱讀!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/36303.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/36303.shtml
英文地址,請注明出處:http://en.pswp.cn/news/36303.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

go內存管理機制

golang內存管理基本是參考tcmalloc來進行的。go內存管理本質上是一個內存池,只不過內部做了很多優化:自動伸縮內存池大小,合理切割內存塊。 基本概念: Page:頁,一塊 8 K大小的內存空間。Go向操作系統申請和…

2.Model、ModelMap和ModelAndView的使用詳解

1.前言 最近SSM框架開發web項目,用得比較火熱。spring-MVC肯定用過,在請求處理方法可出現和返回的參數類型中,最重要就是Model和ModelAndView了,對于MVC框架,控制器Controller執行業務邏輯,用于產生模型數據…

Spring Cloud構建微服務斷路器介紹

什么是斷路器 斷路器模式源于Martin Fowler的Circuit Breaker一文。“斷路器”本身是一種開關裝置,用于在電路上保護線路過載,當線路中有電器發生短路時,“斷路器”能夠及時的切斷故障電路,防止發生過載、發熱、甚至起火等嚴重后果…

【Redis】使用Docker鏡像配置集群時的Operation timed out問題

不知道有沒有小伙伴跟我一樣是使用的Docker鏡像進行Redis集群案例模擬的(三臺虛擬機確實帶不動 ),然后我遇到了一個問題:Could not connect to Redis at 172.17.0.2:6379: Operation timed out 172.17.0.2是我其中一個Redis實例的…

如何測試Linux磁盤的讀寫速度

在Linux系統中也有很多命令可以測試硬盤的讀寫速度指標。以下是幾個常用命令(注意:在執行測試命令之前,請務必備份數據以避免數據丟失! 1、dd 命令 首先掛載磁盤 mount /dev/sdb /testdd 命令可用于進行硬盤讀寫速度測試。 例…

uniapp踩坑之項目:判斷字符串長度自動調整選項卡寬度

利用動態:class來判斷字長調整選項卡uni-data-select 寬度 //html <view><view style"width:100%" :class"checkLength(text)>4 ? textexplode:textshrink"><uni-data-select v-model"value" :localdata"rangeTag"…

android 開發中常用命令

1.反編譯 命令&#xff1a;apktool d <test.apk> -o <folderdir> 其中&#xff1a;test.apk是待反編譯文件的路徑&#xff0c;folderdir是反編譯后的文件的存儲位置。 apktool d -f <test.apk> -o <folderdir> 注意&#xff1a;如果dir已經存在&am…

從零學算法34

34.給你一個按照非遞減順序排列的整數數組 nums&#xff0c;和一個目標值 target。請你找出給定目標值在數組中的開始位置和結束位置。 如果數組中不存在目標值 target&#xff0c;返回 [-1, -1]。 你必須設計并實現時間復雜度為 O(log n) 的算法解決此問題。 示例 1&#xff1…

React Native 在高IOS版本下無法顯示圖片的問題處理

圖片在低ios版本下可以看到圖片&#xff0c;在高版本ios下顯示不了圖片 直接上解決方法 找文件 /node_modules/react-native/Libraries/Image/RCTUIImageViewAnimated.m 修改源碼 原代碼 if (_currentFrame) {layer.contentsScale self.animatedImageScale;layer.contents…

php中nts和ts

PHP語言解析器:官方提供了2種類型的版本&#xff0c;線程安全(TS)版和非線程安全(NTS)版 TS: TS(Thread-Safety)即線程安全&#xff0c;多線程訪問時&#xff0c;采用了加鎖機制&#xff0c;當一個線程訪問該類的某個數據時進行數據加鎖保護&#xff0c;其他線程不能同時進行訪…

您的網站不應該只提供一套通用 API

后端應該提供兩套 API&#xff0c;一套是外部使用的通用 API&#xff0c;服務特定的數據&#xff0c;另一套是自家使用的應用 API&#xff0c;服務特定的頁面。 在當今的web開發中&#xff0c;構建一個提供JSON服務的后端和一個渲染應用程序的前端是很流行的。我不太喜歡&…

【Sklearn】基于決策樹算法的數據分類預測(Excel可直接替換數據)

【Sklearn】基于決策樹算法的數據分類預測&#xff08;Excel可直接替換數據&#xff09; 1.模型原理1.1 模型原理1.2 數學模型 2.模型參數3.文件結構4.Excel數據5.下載地址6.完整代碼7.運行結果 1.模型原理 決策樹是一種基于樹狀結構的分類和回歸模型&#xff0c;它通過一系列…

MySql(干貨)

寫這篇博客的目的不是為了將介紹原理&#xff0c;而是為了Sql中的代碼操作屬實太多了&#xff0c;在這里進行一個匯總&#xff0c;方便查閱&#xff01;&#xff01;&#xff01; Sql分類 分類全稱說明 DDL Data Definintion Language數據定義語言&#xff0c;用來定義數據庫對…

微信小程序(由淺到深)

文章目錄 一. 項目基本配置1. 項目組成2. 常見的配置文件解析3. app.json全局的五大配置4.單個頁面中的page配置5. App函數6.tabBar配置 二. 基本語法&#xff0c;事件&#xff0c;單位1. 語法2. 事件3. 單位 三. 數據響應式修改四 . 內置組件1. button2. image3. input4. 組件…

k8s常用資源管理 控制

目錄 Pod&#xff08;容器組&#xff09;&#xff1a;Pod是Kubernetes中最小的部署單元&#xff0c;可以包含一個或多個容器。Pod提供了一種邏輯上的封裝&#xff0c;使得容器可以一起共享網絡和存儲資源 1、創建一個pod 2、pod管理 pod操作 目錄 創建Pod會很慢 Pod&…

什么是事務,并發帶來的事務問題以及事務隔離級別(圖文詳解)

一、什么是事務&#xff1f; 簡單說就是邏輯上的一組操作&#xff0c;要么都執行&#xff0c;要么都不執行。 舉個例子&#xff0c;假如小明要給小紅轉賬100元&#xff0c;這個轉賬會涉及到兩個關鍵操作&#xff1a;①將小明的余額減少100元。 ②將小紅的余額增加100元 。但…

學習筆記整理-JS-04-流程控制語句

文章目錄 一、條件語句1. if語句的基本使用2. if else if多條件分支3. if語句算法題4. switch語句5. 三元運算符 二、循環語句1. for循環語句2. for循環算法題3. while循環語句4. break和continue5. do while語句 三、初識算法1. 什么是算法2. 累加器和累乘器3. 窮舉法4. 綜合算…

給大家推薦一些文本翻譯、文檔翻譯API接口

最近在項目中要接入文本翻譯和文檔翻譯功能&#xff0c;滿足在工作時使用&#xff0c;又需要了解每個人的使用情況&#xff0c;所以采用了集成翻譯API的方式&#xff0c;我再調研時也查了比較多的資料&#xff0c;總結了我感覺比較好的網站。 推薦網站 1、百度翻譯&#xff0…

設計模式(2)工廠方法模式

一、 1、介紹&#xff1a;定義一個用于創建對象的接口&#xff0c;讓子類決定實例化哪一個類。工廠方法使一個類的實例化延遲到其子類。簡單工廠模式的最大優點在于工廠類中包含了必要的邏輯判斷&#xff0c;根據客戶端的選擇條件動態實例化相關的類&#xff0c;對于客戶端來說…

odoo-034 float 浮點數比較

文章目錄 前提問題解決總結 前提 odoo 版本&#xff1a;13 python&#xff1a;3.6.9 問題 比較銷售訂單行中已送貨跟已開票&#xff0c;在 tree 視圖顯示搜索后的結果。發現搜索條件為已送貨 > 已開票時&#xff0c;結果中會包含已送貨已開票的。 解決 把這兩個值打印出…