資料結構(棧和佇列)
1. 數制轉換
【問題描述】
十進位制數N和其他d進位制數的轉換是計算機實現計算的基本問題,其解決方法很多,其中一個簡單演算法基於下列原理:
N = (N div d) * d +(N mod d)
其中div是整除運算,mod是求餘運算。
例如(2018)10= (3742)8= (7E2)16
【輸入形式】一個十進位制數以及d進位制數(2<=d<=16)
【輸出形式】該十進位制數所對應d進位制數
【樣例輸入】2018 16
【樣例輸出】7E2
#include<iostream>
using namespace std;
void output(int num) {
if(num<10) {
cout<<num;
} else {
char b='A' + num-10;
cout<<b;
}
}
void algorithm(int n,int d) {
if(n<d) {
output(n);
return ;
} else {
algorithm(n/d,d);
output(n%d);
}
}
int main() {
int d,n;
cin>>n>>d;
algorithm(n,d);
return 0;
}
2. 括號匹配
【問題描述】
假設一個算術表示式中可以包含三種括號:圓括號“(”和“)”,方括號“[”和“]”以及花括號“{”和“}”,且這三種括號可按任意的次序巢狀使用,如4.png。判斷給定表示式中所包含括號是否正確配對。
【輸入形式】一個算術表示式(中間沒有空格)。
【輸出形式】該表示式中的括號是否正確配對。
【樣例輸入】( { [ ] }
【樣例輸出】NO
【樣例說明】當括號不匹配時,有可能左括號和有括號等長度不匹配,也有可能左括號長度大於右括號,還有可能是右括號長度大於左括號,所以出棧操作要考慮全面。
#include<iostream>
#include<stack>
#include<string>
using namespace std;
int main() {
string temp;
cin>>temp;
stack<char>tool; //建立字元棧
for(int i=0; i<temp.length(); i++) {
if(temp[i]=='('||temp[i]=='['||temp[i]=='{')//左括號入棧
tool.push(temp[i]);
else if(temp[i]=='['&&tool.top()!=']') {
cout<<"NO"<<endl;
return 0;
} else if(temp[i]=='{'&&tool.top()!='}') {
cout<<"NO"<<endl;
return 0;
} else if(temp[i]=='('&&tool.top()!=')') {
cout<<"NO"<<endl;
return 0;
} else {
tool.pop();
}
}
if(!tool.empty()) {//括號有多餘的未參與匹配
cout<<"NO"<<endl;
return 0;
}
cout<<"YES"<<endl;//滿足條件
return 0;
}
3. 合法序列
假設以I和O分別表示入棧和出棧操作,棧的初態和終態均為空,入棧和出棧的操作序列可表示為僅由I和O組成的序列,稱可以操作的序列為合法序列,否則稱為非法序列。
寫出一個演算法,判定所給的操作序列是否合法。若合法,輸出1,否則輸出0。
【輸入形式】由I和O組成的被判定序列。
【輸出形式】若合法,輸出1,否則輸出0。
【樣例輸入】IOIIOIOO
【樣例輸出】1
#include<iostream>
#include<stack>
#include<string>
using namespace std;
int main() {
stack<char>tool;
string temp;
cin>>temp;
for(int i=0; i<temp.length(); i++) {
if(temp[i]=='I') //為I入棧
tool.push(temp[i]);
else if(tool.empty()) { //棧空
cout<<"0"<<endl;
return 0;
} else { //為 O 出棧
tool.pop();
}
}
if(tool.empty()) {
cout<<"1"<<endl;
} else {
cout<<"0"<<endl;
}
return 0;
}
4. 中綴表示式轉字尾表示式並求值
【問題描述】在表示式求值時,為了處理方便,通常把中綴表示式轉成等價的字尾表示式,然後計算表示式的結果。
【輸入形式】一箇中綴表示式
【輸出形式】表示式的計算結果
【樣例輸入】3*(4+2)/2-5
【樣例輸出】4
【樣例說明】注意運算子是因為狀態
#include <iostream>
#include <math.h>
#include<stdio.h>
using namespace std;
const int StackSize=100;
template <class DataType>
class SeqStack {
private:
DataType data[StackSize];
int top;
public:
SeqStack() {
top=-1;
}
~SeqStack() {}
void push(DataType x); //入棧操作,將元素x入棧
void pop(); //出棧操作
DataType Gettop(); //取棧頂元素
int Empty() {
return top==-1?1:0; //判斷棧是否為空
}
int getSize() {
return top; //返回棧的長度
}
};
template<class DataType>
void SeqStack<DataType>::push(DataType x) {
top++;
data[top]=x;
}
template<class DataType>
void SeqStack<DataType>::pop() {
top--;
}
template<class DataType>
DataType SeqStack<DataType>::Gettop() {
if(top==-1) cout<<"empty";
else
return data[top];
}
bool Number(char ch) { //判斷是否為數字,是則返回true
if((ch-'0')>=0&&(ch-'0')<=9)
return true;
return false;
}
void InPut(char*& str) { //接收輸入的中綴表示式的函式,並簡單判斷是否合法
//cout << "Please Enter What You Want To calculation:" << endl;
while (1) {
cin >> str;
if (Number(str[0])) { //中綴表示式的第一個必定是數字,如果不是,則非法
break;
} else {
cout << "Illegal Input,Please Input Again:";
delete[] str;
}
}
}
int GetPriority(char sy) { //設定各個操作符的優先順序
switch (sy) {
case '#':
return 0;
case '(':
return 1;
case '+':
case '-':
return 3;
case '*':
case '/':
return 5;
case ')':
return 6;
default:
return -1;
}
}
void AddSpace(char*& arr) { //給轉成的字尾表示式的數字和符號新增空格,區分每個字元
*arr = ' ';
arr++;
}
char* GetBack() { //獲取字尾表示式的函式
char* middle = new char[30];
char* back = new char[30];
char* backend = back;
InPut(middle);
SeqStack<char> s;
s.push('#');
while (*middle) {
if (Number(*middle) || *middle == '.') { //如果是數字或者小數的話,直接輸出
*back = *middle;
back++, middle++;
} else {
if (Number(*(back - 1)))//只有他的上一個時數字的話,才繼續給空格
//否則遇到多個操作符,則輸出域會存在多個空格
{
//*back = ' ';
//back++;
AddSpace(back);
}
if (*middle == ')') { //如果右括號的話,輸出所有操作符直到遇到左括號,並拋棄相對應的一堆括號
while (s.Gettop() != '(') {
*back = s.Gettop();
s.pop();
back++;
AddSpace(back);
}
middle++;
s.pop();//拋棄左括號
} else if (*middle == '(') { //遇到左括號,則進入棧
s.push(*middle);
middle++;
} else if (GetPriority(*middle) > GetPriority(s.Gettop())) { //如果棧內的操作符優先順序高於棧外的優先順序,則入棧
s.push(*middle);
middle++;
} else if (GetPriority(*middle) <= GetPriority(s.Gettop()))
//如果棧內的操作符優先順序低於或等於棧外的優先順序,輸出棧內的符號,併入棧棧外的符號
{
*back = s.Gettop();
s.pop();
s.push(*middle);
back++;
middle++;
AddSpace(back);
}
}
}
while (s.Gettop() != '#') { //中綴表示式遍歷完成,但是=棧中還有符號存在,一一出棧輸出
AddSpace(back);
*back = s.Gettop();
s.pop();
back++;
}
*back = '\0';
//cout << "The Back Is: " << backend << endl;
return backend;
}
double GetNumber(char*& arr) {
//因為輸出為char*,所以可能兩位數以上的數字被拆開,此函式為正確得到數字
double sum[10] = { 0 };
int i = 0;
double result = 0;
while (*arr != ' ') {
sum[i] = *arr-48;
i++;
arr++;
}
int k = i - 1;
for (int j = 0; j < i; j++,k--) {
result += (sum[j] * pow(10, k));
}
return result;
}
double Cauculate(char ch, double left, double right) { //各個操作符對應的操作
switch (ch) {
case '+':
return left + right;
case '-':
return left - right;
case '*':
return left * right;
case '/':
return left / right;
default:
return 0;
break;
}
}
double CountBack(char* back) {
SeqStack<double> s;
while (*back) {
if (Number(*back)) { //遇到數字
s.push(GetNumber(back));//將正確的數字入棧
} else if (*back == ' ') {
back++;//遇到空格跳過
} else {
double a = s.Gettop();
s.pop();
double b = s.Gettop();
s.pop();
s.push(Cauculate(*back, b, a));//遇到符號時,取棧頂的第二個數和第一個數求解,併入棧
back++;
}
}
while (s.getSize() >= 2) { //最終棧記憶體在的數大於2時,繼續計算,直到只剩下一個數
double a = s.Gettop();
s.pop();
double b = s.Gettop();
s.pop();
s.push(Cauculate(*back, b, a));
}
//返回這個數字,既是最終結果
return s.Gettop();
}
int main() {
cout<<CountBack(GetBack())<<endl;;
return 0;
}
5. 迴圈佇列的入隊和出隊
在迴圈佇列中設定一個標誌flag,當front=rear且flag=0時為隊空,當front=rear且flag=1時為隊滿。編寫相應的入隊和出隊演算法。
【輸入說明】入隊次數m以及m個入隊元素;(中間用空格隔開)
出隊次數n;
【輸出說明】執行m次入隊操作,如果隊滿輸出“overflow”;在執行n次出隊操作後,列印佇列中的元素:如果佇列為空則輸出“Empty”。
【輸入樣例】
3
5 3 6
2
【輸出樣例】
6
#include <iostream>
using namespace std;
const int MaxSize = 5;
template <class DataType>
class cirQueue {
public:
cirQueue();
bool enQueue(DataType elem);
bool deQueue();
void printQueue();
private:
DataType data[MaxSize];
int front,rear;
int flag;//區別佇列空或滿
};
template <class DataType>
cirQueue<DataType>::cirQueue() {
front = rear = MaxSize-1;
flag = 0;
}
template <class DataType>
bool cirQueue<DataType>::enQueue(DataType elem) {
if(!(front==rear&&flag==1)) {//初始flag=0
rear=(rear+1)%MaxSize;
data[rear]=elem;
if(rear==front&&flag==0)//此時剛好隊滿,至flag為1
flag=1;
return true;
} else {
return false;
}
}
template <class DataType>
bool cirQueue<DataType>::deQueue() {
if(front==rear&&flag==0) {//隊空
return false;
} else {
front=(front+1)%MaxSize;
return true;
}
}
template <class DataType>
void cirQueue<DataType>::printQueue() {
if(front == rear && flag == 0)
cout<<"Empty"<<endl;
else {
int i=(front+1)%MaxSize;
while(i<=rear) {
cout<<data[i]<<" ";
if(i==rear)break;
i = (i+1)%MaxSize;
}
cout<<endl;
}
}
int main() {
cirQueue<int> Q;
int m,n;
cin>>m;
while(m--) {
int elem;
cin>>elem;
bool res = Q.enQueue(elem);
if(!res) {
cout<<"overflow"<<endl;
return 0;
}
}
cin>>n;
while(n--) {
bool res = Q.deQueue();
if(!res) break;
}
Q.printQueue();
return 0;
}
6. 迴圈佇列重新排列順序棧
設順序棧S中有2n個元素,從棧頂到棧底的元素依次為1.png,要求通過一個迴圈佇列重新排列棧中元素,使得從棧頂到棧底的元素依次為2.png。請設計演算法實現該操作,要求空間複雜度和時間複雜度均是O(n)。
【輸入格式】棧的長度(n/2)以及元素(中間用空格隔開)
【輸出格式】經過佇列相應操作後的序列。
【輸入樣例】
3
1 2 3 4 5 6
【輸出樣例】6 4 2 5 3 1
提示:
操作步驟:
1、將所有元素出棧併入隊;
2、依次將佇列元素出隊,如果是偶數結點,則再入隊,如果是奇數結點,則入棧;
3、將奇數結點出棧併入隊;
4、將偶數結點出隊併入棧;
5、將所有元素出棧併入隊;
6、將所有元素出隊併入棧即為所求;
#include <iostream>
#include <stack>
#include <queue>
using namespace std;
stack<int> seqStack;
queue<int> cirQueue;
int n;
void init(int len) {
for(int i=0; i<2*len; ++i) {
int elem;
cin>>elem;
seqStack.push(elem);
}
}
void exchange() {
// 1、將所有元素出棧併入隊;
while(!seqStack.empty()) {
cirQueue.push(seqStack.top());
seqStack.pop();
}
// 2、依次將佇列元素出隊,如果是偶數結點,則再入隊,如果是奇數結點,則入棧;
for(int i=0; i<2*n; i++) {
int temp=cirQueue.front();
cirQueue.pop();
if(i%2==0) {//偶數結點,則再入隊
cirQueue.push(temp);
} else {//是奇數結點,則入棧
seqStack.push(temp);
}
}
//3、將奇數結點出棧併入隊;
while(!seqStack.empty()) {
cirQueue.push(seqStack.top());
seqStack.pop();
}
//4、將偶數結點出隊併入棧;
for(int i=1; i<=n; i++) {
int temp=cirQueue.front();
cirQueue.pop();
seqStack.push(temp);
}
//5、將所有元素出棧併入隊;
while(!seqStack.empty()) {
cirQueue.push(seqStack.top());
seqStack.pop();
}
//6、將所有元素出隊併入棧即為所求;
for(int i=1; i<=2*n; i++) {
int temp=cirQueue.front();
cirQueue.pop();
seqStack.push(temp);
}
}
void printStack() {
while(!seqStack.empty()) {
cout<<seqStack.top()<<" ";
seqStack.pop();
}
cout<<endl;
}
int main() {
cin>>n;
init(n);
exchange();
printStack();
return 0;
}
7. 迴圈鏈佇列的入隊和出隊
假設以不帶頭結點的迴圈連結串列表示非空佇列,並且只設一個指標指向隊尾結點,但不設頭指標。試設計相應的入隊和出隊的演算法。
【輸入說明】
入隊次數m以及m個入隊元素;(中間用空格隔開)
出隊次數n;
【輸出說明】執行m次入隊操作和n次出隊操作後,列印佇列中的元素:如果佇列為空則輸出“Empty”。
【輸入樣例】
3
5 3 6
1
【輸出樣例】
3 6
#include <iostream>
using namespace std;
template <class DataType>
struct node {
DataType data;
node<DataType>* next;
};
template <class DataType>
class cirLinkQueue {
public:
cirLinkQueue();
cirLinkQueue(DataType a[],int n);
void enQueue(DataType elem);
bool deQueue();
void printQueue();
private:
node<DataType>* rear;
};
template <class DataType>
cirLinkQueue<DataType>::cirLinkQueue() {
rear = NULL;
}
template <class DataType>
cirLinkQueue<DataType>::cirLinkQueue(DataType a[],int n) {
if(n == 1) {
rear = new node<DataType>;
rear->data = a[0];
rear->next = rear;
} else {
rear = new node<DataType>;
rear->data = a[0];
rear->next = rear;
for(int i=1; i<n; ++i) {
node<DataType>* s = new node<DataType>;
s->data = a[i];
s->next = rear->next;
rear->next = s;
rear = s;
}
}
}
template <class DataType>
void cirLinkQueue<DataType>::enQueue(DataType elem) {
if(rear==NULL) {// 當前佇列為空
node<DataType> *temp=new node<DataType>;
temp->data=elem;
temp->next=temp;//形成首尾迴圈
rear=temp;
} else {
node<DataType> *temp=new node<DataType>;
temp->data=elem;
temp->next=rear->next;
rear->next=temp;
rear=temp;
}
}
template <class DataType>
bool cirLinkQueue<DataType>::deQueue() {
if(rear==NULL)
return false;
if(rear->next==rear) {
delete rear;
rear=NULL;
return true;
} else {
node<DataType>*s=rear->next;
rear->next=rear->next->next;
delete s;
return true;
}
}
template <class DataType>
void cirLinkQueue<DataType>::printQueue() {
if(rear == NULL)
cout<<"Empty"<<endl;
else {
node<DataType>* p = rear->next;
while(p != rear) {
cout<<p->data<<" ";
p = p->next;
}
cout<<p->data<<endl;
}
}
int main() {
cirLinkQueue<int> Q;
int m,n;
cin>>m;
while(m--) {
int elem;
cin>>elem;
Q.enQueue(elem);
}
cin>>n;
while(n--) {
bool res = Q.deQueue();
if(!res) break;
}
Q.printQueue();
return 0;
}
結語
如果你發現文章有什麼問題,歡迎留言指正。
如果你覺得這篇文章還可以,別忘記點個贊加個關注再走哦。
如果你不嫌棄,還可以關注微信公眾號———夢碼城(持續更新中)。
夢碼在這裡感激不盡!!
相關文章
- 資料結構—棧和佇列資料結構佇列
- 【資料結構】--棧和佇列資料結構佇列
- 資料結構之棧和佇列資料結構佇列
- 資料結構—棧/佇列資料結構佇列
- 資料結構-佇列、棧資料結構佇列
- 【資料結構】棧(Stack)和佇列(Queue)資料結構佇列
- 資料結構二之棧和佇列資料結構佇列
- 資料結構-棧與佇列資料結構佇列
- 資料結構:棧與佇列資料結構佇列
- 資料結構-js實現棧和佇列資料結構JS佇列
- 【資料結構】棧和佇列的總結對比資料結構佇列
- 畫江湖之資料結構【第二話:佇列和棧】佇列資料結構佇列
- 畫江湖之資料結構 [第二話:佇列和棧] 佇列資料結構佇列
- 學習JavaScript資料結構(一)——棧和佇列JavaScript資料結構佇列
- javascript的資料結構快速學-棧和佇列JavaScript資料結構佇列
- JavaScript資料結構之陣列棧佇列JavaScript資料結構陣列佇列
- 畫江湖之資料結構【第二話:佇列和棧】棧資料結構佇列
- 畫江湖之資料結構 [第二話:佇列和棧] 棧資料結構佇列
- 【資料結構】回顧表、棧、佇列資料結構佇列
- 資料結構基礎學習之(棧和佇列)資料結構佇列
- 《資料結構與演算法》——表、棧和佇列資料結構演算法佇列
- 大二資料結構學習3(棧和佇列)資料結構佇列
- 淺談演算法和資料結構(1):棧和佇列演算法資料結構佇列
- 三、資料結構演算法-棧、佇列、優先佇列、雙端佇列資料結構演算法佇列
- Stack and Queue in JavaScript(Javascript中的資料結構之棧和佇列)JavaScript資料結構佇列
- JavaScript的資料結構與演算法(一)——棧和佇列JavaScript資料結構演算法佇列
- 資料結構與演算法-棧與佇列資料結構演算法佇列
- 資料結構-棧&佇列&Deque實現比較資料結構佇列
- php實現基本資料結構之棧、佇列PHP資料結構佇列
- 結構與演算法(02):佇列和棧結構演算法佇列
- 資料結構-佇列資料結構佇列
- 【資料結構-----佇列】資料結構佇列
- 資料結構 - 佇列資料結構佇列
- 一本正經的聊資料結構(3):棧和佇列資料結構佇列
- 演算法系列(六)資料結構之表佇列和棧演算法資料結構佇列
- python資料結構與演算法——棧、佇列與雙端佇列Python資料結構演算法佇列
- 資料結構:特殊的線性表之 棧 & 佇列資料結構佇列
- 資料結構與演算法(三),棧與佇列資料結構演算法佇列