一.队列
结构定义
FIFO:队列是一个先进先出的数据结构;
只允许从队首出元素,从队尾入元素;
head和tail所包含的区间是左闭开的;
入队操作
没用真实将一号元素删除,而是将head指针向后移动一位,进行逻辑上的删除;
出队操作
将新元素储存在队尾指针所在的位置,并将队尾指针向后移动一位;
队列的假溢出
有三个空位,但是tail超出范围;
此时可以引入循环队列:当tail超出范围时让tail重新指向0;
循环队列
解决了队列的假溢出问题;
代码实现
链表的顺序表实现:
java
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
typedef struct Vector {
int* data;
int size;
}vector;
vector* initVector(int n) {
vector* v = (vector*)malloc(sizeof(vector));
v->size = n;
v->data = (int*)malloc(n * sizeof(int));
return v;
}
void clearVector(vector* v) {
if (v == NULL) return;
free(v->data);
v->data = NULL;
free(v);
v = NULL;
return;
}
int vectorSeek(vector* v,int pos) {
if (pos < 0 || pos >= v->size) return -1;
return v->data[pos];
}
int insertVector(vector* v, int pos, int val) {
if (pos < 0 || pos >= v->size) return -1;
v->data[pos] = val;
return 1;
}
typedef struct Queue {
vector* data;
int size, head, tail, count;
}Queue;
Queue* initQueue(int n) {
Queue* q = (Queue*)malloc(n * sizeof(Queue));
q->data = initVector(n);
q->count = q->head = q->tail = 0;
q->size = n;
return q;
}//初始化大小为n的队列
void clearQueue(Queue* q) {
if (q == NULL) return;
clearVector(q->data);
free(q);
q = NULL;
return;
}
int empty(Queue* q) {
return q->count == 0;
}//判断队列是否是空的
int push(Queue* q, int val) {
if (q->count == q->size) return 0;
insertVector(q->data, q->tail, val);
q->tail += 1;
if (q->tail == q->size) q->tail = 0;
q->count += 1;
return 1;
}//压入队尾元素
//返回值代表是否push成功
int front(Queue* q) {
return vectorSeek(q->data, q->head);
}//查看队首元素
int pop(Queue* q) {
if (empty(q)) return 0;
q->head += 1;
if (q->head == q->size) q->head = 0;
q->count -= 1;
return 1;
}//弹出队首元素,返回0代表不成功
void outputQueue(Queue* q) {
printf("Queue:\n");
for (int i = 0; i < q->count; i++) {
printf("%4d", vectorSeek(q->data, (q->head + i) % q->size));
}
printf("\n");
return;
}
int main() {
srand(time(0));
#define MAX_OP 10
Queue* q = initQueue(5);
for (int i = 0; i < MAX_OP; i++) {
int op = rand() % 5, val = rand() % 100;//1234 push,0 pop
switch (op) {
case 0:
printf("front of q:%d\n", front(q));
pop(q);
break;
case 1:
case 2:
case 3:
case 4:
printf("push %d to q\n", val);
push(q, val);
break;
}
outputQueue(q);
}
return 0;
}
链表的链表实现:
不存在队列假溢出问题,不用再使用循环链表了,size参数可以省略;
但是可以再记录count来判断队列是否为空队列;
队列的头尾指针可以被省略;
java
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
typedef struct Node {
int data;
Node* next;
}Node;
typedef struct LinkList{
Node head, *tail;//注意这里实现的是有头链表,head并不存储数据
int size;
}LinkList;
LinkList* initLinkList() {
LinkList* l = (LinkList*)malloc(sizeof(LinkList));
l->head.next = NULL;
l->tail = &(l->head);
return l;
}
void clearLinkList(LinkList* l) {
Node* p = l->head.next, *q;
while (p) {
q = p;
p = p->next;
free(q);
q = NULL;
}
free(l);
l = NULL;
}
int frontList(LinkList* l) {
if (l->head.next == NULL) return 0;
return l->head.next->data;
}
Node* getNewNode(int val) {
Node* node = (Node*)malloc(sizeof(Node));
node->data = val;
node->next = NULL;
return node;
}
int insertTail(LinkList* l, int val) {
Node* node = getNewNode(val);
l->tail->next = node;
l->tail = node;
return 1;
}
int emptyList(LinkList* l) {
return l->head.next == NULL;
}
int eraseHead(LinkList* l) {
if (emptyList(l)) return 0;
Node* p = l->head.next;
l->head.next = l->head.next->next;
if (p == l->tail) l->tail = &(l->head);
free(p);
return 1;
}
typedef struct Queue {
LinkList* l;
int count;
}Queue;
Queue* initQueue(int n) {
Queue* q = (Queue*)malloc(n * sizeof(Queue));
q->l = initLinkList();
q->count = 0;
return q;
}//初始化大小为n的队列
void clearQueue(Queue* q) {
if (q == NULL) return;
clearLinkList(q->l);
free(q);
q = NULL;
return;
}
int empty(Queue* q) {
return q->count == 0;
}//判断队列是否是空的
int push(Queue* q, int val) {
insertTail(q->l, val);
q->count += 1;
return 1;
}//压入队尾元素
//返回值代表是否push成功
int front(Queue* q) {
if (empty(q)) return -1;//代表查找首元素失败
return frontList(q->l);
}//查看队首元素
int pop(Queue* q) {
if (empty(q)) return 0;
eraseHead(q->l);
q->count -= 1;
return 1;
}//弹出队首元素,返回0代表不成功
void outputQueue(Queue* q) {
printf("Queue:\n");
Node* p = q->l->head.next;
for (int i = 0; i < q->count; i++) {
printf("%4d", p->data);
p = p->next;
}
printf("\n");
return;
}
int main() {
srand(time(0));
#define MAX_OP 10
Queue* q = initQueue(5);
for (int i = 0; i < MAX_OP; i++) {
int op = rand() % 5, val = rand() % 100;//1234 push,0 pop
switch (op) {
case 0:
printf("front of q:%d\n", front(q));
pop(q);
break;
case 1:
case 2:
case 3:
case 4:
printf("push %d to q\n", val);
push(q, val);
break;
}
outputQueue(q);
}
return 0;
}
二.栈
结构定义
栈是一种先进后出(FILO)的数据结构;
出栈操作
入栈操作
代码实现
cpp
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
typedef struct Stack {
int* data;
int size, top;
}Stack;
Stack* initStack(int n) {
Stack* s = (Stack*)malloc(sizeof(Stack));
s->data = (int*)malloc(n * sizeof(Stack));
s->size = n;
s->top = -1;//!!!
return s;
}
void clearStack(Stack* s) {
if (s == NULL) return;
free(s->data);
s->data = NULL;
free(s);
s = NULL;
return;
}
int empty(Stack* s) {
return (s->top == 1);
}
int top(Stack* s) {
if (empty(s)) return 0;
return s->data[s->top];
}
int push(Stack* s, int val) {
if (s->top + 1 == s->size) return 0;
s->top += 1;
s->data[s->top] = val;
return 1;
}
int pop(Stack* s) {
if (empty(s)) return 0;
s->top -= 1;
return 1;
}
void outputStack(Stack* s) {
printf("Stack:");
for (int i = s->top; i >= 0; i--) {
printf("%4d", s->data[i]);
}
printf("\n\n");
return;
}
int main() {
srand(time(0));
#define MAX_OP 10
Stack* s = initStack(5);
for (int i = 0; i < MAX_OP; i++) {
int op = rand() % 3;//0 pop;1 2 push;
int val = rand() % 100;
switch (op) {
case 0:
printf("pop Stack, item = %d\n", top(s));
pop(s);
break;
case 1:
case 2:
printf("push Stack, item = %d\n", val);
push(s, val);
break;
}
outputStack(s);
}
return 0;
}
题目练习
cpp
class Solution {
public:
bool isValid(string s) {
int n = s.size();
//if(n % 2) return false;
unordered_map<char, char> pairs = {
{')', '('},
{']', '['},
{'}', '{'}
};
stack<char> stk;
for(char ch: s) {
if(pairs.count(ch)) {
if(stk.empty() || stk.top() != pairs[ch]) {
return false;
}
stk.pop();
}
else {
stk.push(ch);
}
}
return stk.empty();
}
};
栈的深入理解:
**思考:**如果简化成只有一种括号,不用栈怎么实现上述题目的要求.
结论:
1.在任意一个位置上,左括号数量>=右括号数量;
2.在最后一个位置上,左括号数量==右括号数量;
3.程序中只需要记录左右括号的数量即可;
其中lnum的作用相当于栈顶指针top;
思考:
1.+1可以等价为进,-1可以等价为出;
2.一对()可以看成完整的一个事件;
3.(())可以看成事件与事件之间的完全包含关系;
4.由括号的等价变换,得到了一个新的数据结构;
栈:可以处理具有完全包含关系的问题.
三.栈和队列的应用
刷题记录
程序调用关系 - 题目 - Online Judge (haizeix.com)
cpp
//#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <queue>
#include <string>
#include <vector>
using namespace std;
int main(){
int n;
int flag = 0;
cin >> n;
vector<string> ops(n), s;
string target;
for (int i = 0; i < n; i++) cin >> ops[i];
cin >> target;
for (int i = 0; i < n; i++) {
if (target == ops[i]) {
s.push_back(ops[i]);
flag = 1;
break;
}
if (ops[i] == "return") {
s.pop_back();
}
else {
s.push_back(ops[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;
}