队列(顺序表实现)
#include<iostream>
#include<time.h>
using namespace std;
//采用顺序表来实现队列,因此先封装一个顺序表SqList
typedef struct SqList
{
int* data;
int size;
}SqList;
SqList* InitSqList(int n)
{
SqList* q = (SqList*)malloc(sizeof(SqList));
q->data = (int*)malloc(sizeof(int) * n);
q->size = n;
return q;
}
void InsertSqList(SqList*q, int pos, int val)
{
if (pos<0 || pos>q->size)
{
cout << "插入位置不合法" << endl;
return;
}
for (int i = q->size - 1; i >= pos; i--)
{
q->data[i + 1] = q->data[i];
}
q->data[pos] = val;
return;
}
int GetSqList(SqList* q, int pos)
{
if (pos<0 || pos>q->size)
{
cout << "查看位置不合法" << endl;
return -1;
}
return q->data[pos];
}
void ClearSqList(SqList*q)
{
if (q == NULL) return;
free(q->data);
free(q);
return;
}
typedef struct Queue
{
SqList* data;//队列的数据存储区
int size;//队列的大小
int head, tail;//队列的头尾指针
int count;//队列里的元素数量
}Queue;
//队列的初始化操作,传入队列的大小
Queue* InitQueue(int n)
{
Queue* q = (Queue*)malloc(sizeof(Queue));//申请出一个队列空间
q->data = InitSqList(n);
q->size = n;
q->head = q->tail = q->count = 0;
return q;
}
//判断队列是否为空
bool empty(Queue* q)
{
return q->count == 0;
}
//队列的插入操作,即入队;传入待操作队列和待插入元素
bool push(Queue* q, int val)
{
if (q->count == q->size)
{
cout << "队列已满,入队失败" << endl;
return false;
}
InsertSqList(q->data, q->tail, val);
q->tail += 1;//将tail指针向后移动一位
if (q->tail == q->size) q->tail = 0;//规避假溢出情况
q->count += 1;
return true;
}
//队列的删除操作,即出队;传入待操作队列
bool pop(Queue* q)
{
if (empty(q))
{
cout << "队列为空,出队失败" << endl;
return false;
}
q->head += 1;
q->count -= 1;
return true;
}
//查看队首元素
int front(Queue* q)
{
if (q->count == 0) return -1;
return GetSqList(q->data, q->head);
}
//队列的销毁操作,传入待销毁的队列
void ClearQueue(Queue* q)
{
if (NULL == q)
{
cout << "不存在该队列" << endl;
return;
}
ClearSqList(q->data);
free(q);
return;
}
//队列的输出操作
void CoutQueue(Queue* q)
{
for (int i = 0; i < q->count; i++)
{
printf("%-4d", GetSqList(q->data, (q->head+i)%q->size));
}
cout << endl;
cout << endl;
return;
}
int main()
{
srand(time(0));
Queue* q = InitQueue(5);
for (int i = 0; i < 7; i++)
{
int op = rand() % 5;
int val = rand() % 100;
switch (op)
{
case 0:
case 1:
case 2:
case 3:
cout << "入队:" << val << endl;
push(q, val);
break;
case 4:
cout << "出队:" << front(q) << endl;
pop(q);
break;
}
CoutQueue(q);
}
return 0;
}
用顺序表实现的循环队列示意图:
初始化
//封装了顺序表结构
SqList* InitSqList(int n)
{
SqList* q = (SqList*)malloc(sizeof(SqList));
q->data = (int*)malloc(sizeof(int) * n);
q->size = n;
return q;
}
//队列的初始化操作,传入队列的大小
Queue* InitQueue(int n)
{
Queue* q = (Queue*)malloc(sizeof(Queue));//申请出一个队列空间
q->data = InitSqList(n);
q->size = n;
q->head = q->tail = q->count = 0;
return q;
}
入队
//封装了顺序表结构
void InsertSqList(SqList*q, int pos, int val)
{
if (pos<0 || pos>q->size)
{
cout << "插入位置不合法" << endl;
return;
}
for (int i = q->size - 1; i >= pos; i--)
{
q->data[i + 1] = q->data[i];
}
q->data[pos] = val;
return;
}
//队列的插入操作,即入队;传入待操作队列和待插入元素
bool push(Queue* q, int val)
{
if (q->count == q->size)
{
cout << "队列已满,入队失败" << endl;
return false;
}
InsertSqList(q->data, q->tail, val);
q->tail += 1;//将tail指针向后移动一位
if (q->tail == q->size) q->tail = 0;//规避假溢出情况
q->count += 1;
return true;
}
出队
//封装了顺序表的结构
int GetSqList(SqList* q, int pos)
{
if (pos<0 || pos>q->size)
{
cout << "查看位置不合法" << endl;
return -1;
}
return q->data[pos];
}
//队列的删除操作,即出队;传入待操作队列
bool pop(Queue* q)
{
if (empty(q))
{
cout << "队列为空,出队失败" << endl;
return false;
}
q->head += 1;
q->count -= 1;
return true;
}
运行结果:
出队:-1
队列为空,出队失败
入队:76
76
入队:19
76 19
入队:50
76 19 50
入队:2
76 19 50 2
入队:74
76 19 50 2 74
入队:46
队列已满,入队失败
76 19 50 2 74
队列(链表实现)
#include<iostream>
#include<time.h>
using namespace std;
//采用链表来实现队列,因此先封装一个顺序表SqList
typedef struct ListNode
{
ListNode* next;
int data;
}ListNode;
typedef struct LinkList
{
ListNode* tail;//指向尾节点
ListNode head;//定义一个头节点,头节点中不存储数据
}LinkList;
LinkList* InitList()
{
LinkList* L = (LinkList*)malloc(sizeof(LinkList));
L->head.next = NULL;
L->tail = &(L->head);
return L;
}
void ClearList(LinkList* L)
{
ListNode* q = L->head.next;
ListNode* p;
while (q)
{
p = q->next;
free(q);
q = p;
}
free(L);
return;
}
int GetList(LinkList*L)
{
return L->head.next->data;
}
//尾插法
void InsertList(LinkList* L, int val)
{
ListNode* node = (ListNode*)malloc(sizeof(ListNode));
node->data = val;
node->next = NULL;
L->tail->next = node;
L->tail = node;
return;
}
//删除第一个节点
void EraseList(LinkList* L)
{
ListNode* p = L->head.next;
L->head.next = p->next;
if (p == L->tail) L->tail = &(L->head);
free(p);
return;
}
typedef struct Queue
{
LinkList* L;//将底层结构改为链表后就不会出现假溢出
int count;
}Queue;
//初始化操作
Queue* InitQueue()
{
Queue* q = (Queue*)malloc(sizeof(Queue));
q->L = InitList();
q->count = 0;
return q;
}
//判空操作
bool empty(Queue* q)
{
return q->count == 0;
}
//查看队首元素
int front(Queue* q)
{
if (empty(q))
{
cout << "队列为空" << endl;
return -1;
}
return GetList(q->L);
}
//入栈
void push(Queue*q,int val)
{
InsertList(q->L, val);
q->count += 1;
return;
}
//出栈
void pop(Queue* q)
{
if (empty(q)) return;
EraseList(q->L);
q->count -= 1;
return;
}
//销毁操作
void clear(Queue* q)
{
if (NULL == q) return;
ClearList(q->L);
free(q);
return;
}
//队列的输出操作
void CoutQueue(Queue* q)
{
ListNode* p = q->L->head.next;
for (int i = 0; i < q->count; i++)
{
printf("%-4d", p->data);
p = p->next;
}
cout << endl;
cout << endl;
return;
}
int main()
{
srand(time(0));
Queue* q = InitQueue();
for (int i = 0; i < 7; i++)
{
int op = rand() % 5;
int val = rand() % 100;
switch (op)
{
case 0:
case 1:
case 2:
case 3:
cout << "入队:" << val << endl;
push(q, val);
break;
case 4:
cout << "出队:" << front(q) << endl;
pop(q);
break;
}
CoutQueue(q);
}
return 0;
}
初始化
//封装链表的结构
LinkList* InitList()
{
LinkList* L = (LinkList*)malloc(sizeof(LinkList));
L->head.next = NULL;
L->tail = &(L->head);
return L;
}
//初始化操作
Queue* InitQueue()
{
Queue* q = (Queue*)malloc(sizeof(Queue));
q->L = InitList();
q->count = 0;
return q;
}
入队
//尾插法
void InsertList(LinkList* L, int val)
{
ListNode* node = (ListNode*)malloc(sizeof(ListNode));
node->data = val;
node->next = NULL;
L->tail->next = node;
L->tail = node;
return;
}
//入栈
void push(Queue*q,int val)
{
InsertList(q->L, val);
q->count += 1;
return;
}
出队
//删除第一个节点
void EraseList(LinkList* L)
{
ListNode* p = L->head.next;
L->head.next = p->next;
if (p == L->tail) L->tail = &(L->head);
free(p);
return;
}
//出栈
void pop(Queue* q)
{
if (empty(q)) return;
EraseList(q->L);
q->count -= 1;
return;
}
运行结果:
入队:22
22
出队:22
队列为空
出队:-1
入队:10
10
入队:65
10 65
入队:51
10 65 51
出队:10
65 51
栈(顺序表实现)
#include<iostream>
#include<time.h>
using namespace std;
//定义栈结构
typedef struct Stack
{
int* data;//数据存储区
int top; //栈顶指针
int size; //栈大小
}Stack;
//初始化栈的大小,n代表栈能容纳的数据个数
Stack* InitStack(int n)
{
Stack* s = (Stack*)malloc(sizeof(Stack));
s->data = (int*)malloc(sizeof(int) * n);
s->size = n;
s->top = -1;//由于top永远指向栈顶元素,初始时刻栈中没有元素,故为-1
return s;
}
//判空操作
bool empty(Stack* s)
{
return s->top == -1;
}
//查看栈顶元素
int GetTop(Stack* s)
{
if (empty(s))
{
cout << "栈为空,无法查看栈顶元素" << endl;
return -1;
}
return s->data[s->top];
}
//入栈操作
bool push(Stack* s, int val)
{
if (s->top+1 == s->size)
{
cout << "栈满,入栈失败" << endl;
return false;
}
s->top += 1;
s->data[s->top] = val;
return true;
}
//出栈操作
bool pop(Stack* s)
{
if (empty(s))
{
cout << "栈为空,出栈失败" << endl;
return false;
}
s->top -= 1;
return true;
}
//销毁操作
void ClearStack(Stack* s)
{
if (NULL == s)
{
return;//为空表示不存在这么一个栈,那么就直接返回
}
free(s->data);
free(s);
return;
}
//输出操作
void CoutStack(Stack* s)
{
cout << "Satck(顶->底):";
for (int i = s->top; i >= 0; i--)
{
printf("%-4d", s->data[i]);
}
cout << endl;
cout << endl;
return;
}
int main()
{
srand(time(0));
Stack* s = InitStack(4);
for (int i = 0; i < 7; i++)
{
int op = rand() % 4;
int val = rand() % 100;
switch (op)
{
case 0:
case 1:
case 2:
cout << "入栈:" << val << endl;
push(s, val);
break;
case 3:
cout << "出栈:" << GetTop(s) << endl;
pop(s);
break;
}
CoutStack(s);
}
ClearStack(s);
return 0;
}
初始化
//初始化栈的大小,n代表栈能容纳的数据个数
Stack* InitStack(int n)
{
Stack* s = (Stack*)malloc(sizeof(Stack));
s->data = (int*)malloc(sizeof(int) * n);
s->size = n;
s->top = -1;//由于top永远指向栈顶元素,初始时刻栈中没有元素,故为-1
return s;
}
入栈
//入栈操作
bool push(Stack* s, int val)
{
if (s->top+1 == s->size)
{
cout << "栈满,入栈失败" << endl;
return false;
}
s->top += 1;
s->data[s->top] = val;
return true;
}
出栈
//出栈操作
bool pop(Stack* s)
{
if (empty(s))
{
cout << "栈为空,出栈失败" << endl;
return false;
}
s->top -= 1;
return true;
}
相关习题:
有效的括号(Leecode-20):
给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串 s
,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
示例:
输入:s = "()" 输出:true
输入:s = "()[]{}" 输出:true
输入:s = "(]" 输出:false
/*解题思路:遇到左括号就进栈,
遇到右括号就和栈顶的左括号做匹配,
如果成功,栈顶元素出栈;
如果失败,则说明括号序列不合法。
*/
/*解题难点:①如何设计这个栈?
用数组进行模拟
②如何标记左括号、右括号?
左括号就是( [ {右括号就是:) } ]无需标记
③什么情况返回true,什么情况返回false
1.待比较括号与栈顶括号不匹配返回false;
2.遍历完待比较括号但是栈内还存在括号,返回false;
3.其余情况返回true。
*/
class Solution
{
public:
bool isValid(string s)
{
char str[10000] = { 0 };
int top = 1, flag = 0;//将top设为1而不是0,是为了防止top-1越界
for (int i = 0; i < s.length(); i++)
{
if (s[i] == '(' || s[i] == '{' || s[i] == '[')
{
str[top] = s[i];
top += 1;
}
else
{
switch (s[i])
{
case ')':
if (str[top - 1] == '(')
{
top -= 1;
str[top] = 0;
}
else
{
flag = 1;
}
break;
case '}':
if (str[top - 1] == '{')
{
top -= 1;
str[top] = 0;
}
else
{
flag = 1;
}
break;
case ']':
if (str[top - 1] == '[')
{
top -= 1;
str[top] = 0;
}
else
{
flag = 1;
}
break;
}
}
if (flag)
{
return false;
break;
}
}
for (int i = 0; i < 10000; i++)
{
if (str[i] != 0)
{
return false;
break;
}
}
return true;
}
};
对栈的深入理解
如果将上个问题中的三种括号变为一种括号:那么问题的解决方式如下
1.在最后一个位置上,左括号数量==右括号数量,true
2.程序中只需要记录左括号数量和右括号数量即可
解题代码如下:
class Solution
{
public:
bool isValid(string s)
{
int top = 0;//栈顶指针
for (int i = 0; i < s.length(); i++)
{
switch (s[i])
{
case '(':
++top;
break;
case ')':
--top;
break;
}
if (top >= 0)
continue;
return false;
}
return top == 0;
}
};
总结:
①+1可以等价为【进】or【发生】,-1可以等价为【出】or【解决】
②一对()可以等价为一个完整的事件
③(())可以看作事件与事件之间的完全包含关系
再深入一点:当我们遇见这种主从结构(从整体到部分的结构)的时候,大概率就会用到栈来解决,也就是说:栈适合用来解决具有完全包含关系的问题。
程序调用关系(HZOJ-595):
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main()
{
int n, flag = 0;
cin >> n;
vector<string>v(5), s;//v是存储函数名的数组,s是模拟栈的数组
string goal;//待查找函数
for (int i = 0; i < n; i++)
{
cin >> v[i];
}
cin >> goal;
for (int i = 0; i < n; i++)
{
if (goal == v[i])
{
s.push_back(v[i]);
flag = 1;
break;
}
if (v[i] == "return")
{
s.pop_back();
}
else
{
s.push_back(v[i]);
}
}
if (flag)
{
for (int i = 0; i < s.size(); i++)
{
if (i) cout << "->";
cout << s[i];
}
cout << endl;
}
else
{
cout << "NOT REFERENCED" << endl;
}
return 0;
}
2020年数据结构41题(HZOJ-838):
定义三元组(a,b, c)(a,b,c 均为正数)的距离 D=|a-b|+|b-c|+|c-a|。给定 3 个非空整数集合 S1, S2 ,S3, 按升序分别存储在 3 个数组中。请设计一个尽可能高效的算法,计算并输出所有可能的三元组(a, b, c)(a∈S1,b∈S2,c∈S3)中的最小距离。例如 S1={-1, 0, 9}, S2={-25,-10,10,11},S3={2,9,17,30,41},则最小距离为 2,相应的三元组为(9,10,9)。
输入:输入三个参数,分别为存储三个非空集合的队列
输出:返回一个整形值,表示所有可能的三元组(a, b, c)(a∈S1,b∈S2,c∈S3)中的最小距离
#include <iostream>
#include <cstdlib>
#include <queue>
using namespace std;
int min_num(int a, int b, int c)
{
if (a > b) swap(a, b);
if (a > c) swap(a, c);
return a;
}
int func(queue<int> que1, queue<int> que2, queue<int> que3)
{
int ans = 0x3f3f3f3f;
while (!que1.empty() && !que2.empty() && !que3.empty())
{
int a = que1.front(), b = que2.front(), c = que3.front();
int temp_ans = abs(a - b) + abs(a - c) + abs(b - c);
if (temp_ans < ans) ans = temp_ans;
int d = min_num(a, b, c);
if (a == d) que1.pop();
if (b == d)que2.pop();
if (c == d)que3.pop();
}
return ans;
}
int main() {
int m, n, k, x;
queue<int> que1, que2, que3;
cin >> m >> n >> k;
for (int i = 0; i < m; i++)
{
cin >> x;
que1.push(x);
}
for (int i = 0; i < n; i++)
{
cin >> x;
que2.push(x);
}
for (int i = 0; i < k; i++)
{
cin >> x;
que3.push(x);
}
cout << func(que1, que2, que3) << endl;
return 0;
}
比较含退格的字符串(Leetcode-844):
给定 s
和 t
两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true
。#
代表退格字符。
chuo
#include <iostream>
#include <cstdlib>
#include <stack>
using namespace std;
class Solution
{
public:
void pushStack(string& s, stack<char>& s1)
{
for (int i = 0; s[i]; i++)
{
if (s[i] == '#')
{
if (!s1.empty())
s1.pop();
}
else
s1.push(s[i]);
}
return;
}
bool backspaceCompare(string s, string t)
{
stack<char>s1, s2;
pushStack(s, s1);
pushStack(t, s2);
if (s1.size() != s2.size())
{
return false;
}
while (!s1.empty())
{
if (s1.top() != s2.top())
return false;
s1.pop(), s2.pop();
}
return true;
}
};
火车进栈 (HZOJ-263):
有n列火车按1到n的顺序从东方左转进站,这个车站是南北方向的,它虽然无限长,只可惜是一个死胡同,而且站台只有一条股道,火车只能倒着从西方出去,而且每列火车必须进站,先进后出。
进站的火车编号顺序为 1∼n,现在请你按火车编号从小到大的顺序,输出前20种可能的出站方案。
#include<iostream>
#include<string>
#include<algorithm>
#include<stack>
#include<vector>
using namespace std;
bool isValid(int a[], int n)
{
stack<int>s;
int x = 1;//代表当前可以入栈的最小值
for (int i = 0; i < n; i++)
{
//当栈顶元素小于当前元素时,当前元素可以入栈
if (s.empty()||s.top() < a[i])
{
while (x <= a[i])
{
s.push(x);
x += 1;
}
}
if (s.empty() || s.top() != a[i])
{
return false;
}
s.pop();
}
return true;
}
int main()
{
int n, a[25], count = 20;
cin >> n;
for (int i = 0; i < n; i++)
{
a[i] = i + 1;
}
do
{
//判断输出序列是否合法
if (isValid(a, n))
{
for (int i = 0; i < n; i++)
{
cout << a[i];
}
cout << endl;
count -= 1;
}
} while (next_permutation(a, a + n)&&count);
return 0;
}
验证栈序列(Leetcode-946):
给定 pushed
和 popped
两个序列,每个序列中的 值都不重复,只有当它们可能是在最初空栈上进行的推入 push 和弹出 pop 操作序列的结果时,返回 true
;否则,返回 false
。
class Solution
{
public:
bool validateStackSequences(vector<int>& pushed, vector<int>& popped)
{
int x = 0;//代表入栈指针的下标
int n = pushed.size();
stack<int>s;
for (int i = 0; i < n; i++)
{
//判断入栈的情况
if (s.empty() || s.top() != popped[i])
{
while (x < pushed.size() && pushed[x] != popped[i])
{
s.push(pushed[x]);
x += 1;
}
if (x == pushed.size())//说明把所有元素都压进去了
{
return false;
}
s.push(pushed[x]);
x += 1;
}
s.pop();
}
return true;
}
};