C/C++栈和队列

一.队列

结构定义

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;
}

题目练习

20. 有效的括号 - 力扣(LeetCode)

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;
}
相关推荐
带多刺的玫瑰41 分钟前
Leecode刷题C语言之统计不是特殊数字的数字数量
java·c语言·算法
爱敲代码的憨仔42 分钟前
《线性代数的本质》
线性代数·算法·决策树
yigan_Eins1 小时前
【数论】莫比乌斯函数及其反演
c++·经验分享·算法
阿史大杯茶1 小时前
AtCoder Beginner Contest 381(ABCDEF 题)视频讲解
数据结构·c++·算法
დ旧言~2 小时前
【高阶数据结构】图论
算法·深度优先·广度优先·宽度优先·推荐算法
张彦峰ZYF2 小时前
投资策略规划最优决策分析
分布式·算法·金融
The_Ticker2 小时前
CFD平台如何接入实时行情源
java·大数据·数据库·人工智能·算法·区块链·软件工程
爪哇学长3 小时前
双指针算法详解:原理、应用场景及代码示例
java·数据结构·算法
Dola_Pan3 小时前
C语言:数组转换指针的时机
c语言·开发语言·算法
繁依Fanyi3 小时前
简易安卓句分器实现
java·服务器·开发语言·算法·eclipse