数据结构精解(4):栈和队列

本文介绍了栈和队列的概念及其在C语言中的实现,包括栈的初始化、压栈、弹栈等操作,并展示了如何使用栈进行数制转换、括号匹配和表达式求值。同时,提到了队列的特性以及循环队列的概念。文章通过实例代码详细阐述了这些数据结构的应用。
摘要由CSDN通过智能技术生成

栈(stack)是限定仅在表尾进行插入或删除操作的线性表,因此,对于栈来说,表尾端有其特殊含义,称为栈顶,相应的,表头端称为栈底,不含元素的栈称为空栈

栈有一个重要的性质,就是先进后出,First ln Last Out(FILO)。

给几个元素,求其合法的出栈顺序个数,采用卡特兰数(1 / (n + 1)) * C[n, 2n]

构造代码(C)

#include <stdio.h>
#include <stdlib.h>

typedef struct Stack {
	int * data;
	int top;
	int size;
};
Stack initStack(int n) {
	Stack* s = (Stack*)malloc(sizeof(Stack));
	s->data = (int*)malloc(sizeof(int));
	s->top = -1; // 当有元素进来的时候变成0
	s->size = n; // 为栈分配的初始大小
	return s;
}
Stack* freeStack(Stack* s) {
	if (!s) return s;
	free(s->data);
	free(s);
	return NULL;
}
int push(Stack* s, int n) {
	if (!s) {
		return 0;
	}
	if (s->top == s->size - 1){
		if (!expand(s)) {
			return 0;
		}
		else {
			return 1;
		}
	}
	s->data[++s->top] = n;
	return 1;
}
int isEmpty(Stack* s) {
	return !s || s->top == -1;
}
int pop(Stack* s) {
	return s->data[s->top--];
}
void showStack(Stack* s) {
	while (isEmpty(s)) {
		return;
	}
	int i = 0;
	for (; i <= s->top; i++) {
		printf("%d,", s->data[i]);
    }
}
// 栈的扩容
int expand(Stack* s) {
	if (!s) {
		return 0;
	}
	int expSize = s->size;
	int* tmp = NULL;
	while (expSize) {
		tmp = (int*)realloc(s->data, sizeof(int) * (s->size + expsize));
		if (tmp) { // 申请成功
			break;
		}
		expSize >>= 1;
	}
	if (!tmp) {
		return 0;
	}
	s->data = tmp;
	s->size += expSize;
	return 1;
}

栈的基本应用

一个一个写构造太麻烦了,我直接用cpp的STL吧(C++STL里面的stack和queue是适配器,不是容器,他们是从deque或者vector的一部分构成的)

数制转换
#include <iostream>
#include <stack>

std::stack<int> sCon;

int main() {
    int inputN;
    std::cin >> inputN;
    while (inputN) {
        sCon.push(inputN % 8);
        inputN /= 8;
    }
    while (!sCon.empty()) {
        std::cout << sCon.top() << std::ends;
        sCon.pop();
    }
    return 0;
}
括号匹配

有效的括号

class Solution {
public:
    bool isValid(string s) {
        stack<int> sk;
        for (int i = 0; i < s.size(); i++) {
            if (s[i] == '(') sk.push(')');
            else if (s[i] == '{') sk.push('}');
            else if (s[i] == '[') sk.push(']');
            /*
            sk.empty()这一个是因为当右括号把相对应的左括号都取出来后,
            不是上面的三种左括号,而是进来了一个右括号,但是栈为空,说明没有匹配
            该右括号的左括号了,因此这个右括号冗余了,因此返回错误。
            */
            else if (sk.empty() || sk.top() != s[i]) return false;
            else sk.pop();
        }
        return sk.empty();
    }
};
表达式求值
#include <iostream>
#include <stack>
#include <string>
#include <ctype.h>
#include <math.h>

std::stack<int> sNum;
std::stack<char> sSymbol;

int main() {
    std::string inputStr;
    std::cin >> inputStr;
    for (int i = 0; i < inputStr.size(); i++) {
        if (isdigit(inputStr[i])) {
            sNum.push(inputStr[i] - '0');
        }
        else {
            if (inputStr[i] != ')') {
                sSymbol.push(inputStr[i]);
            }
            else if (inputStr[i] == ')'){
                char sTop = sSymbol.top();
                sSymbol.pop();
                while (sTop != '(') {
                    int f1 = sNum.top();
                    sNum.pop();
                    int f2 = sNum.top();
                    sNum.pop();
                    int f = 0;
                    if (sTop == '+') {
                        f = f1 + f2;
                    } else if (sTop == '-') {
                        f = f1 - f2;
                    } else if (sTop == '*') {
                        f = f1 * f2;
                    } else if (sTop == '/') {
                        f = f1 / f2;
                    } else if (sTop == '^') {
                        f = pow(f1, f2);
                    }
                    sNum.push(f);
                    sTop = sSymbol.top();
                    sSymbol.pop();
                }
            }
        }
    }
    while (!sSymbol.empty()) {
        char sTop = sSymbol.top();
        sSymbol.pop();
        int f1 = sNum.top();
        sNum.pop();
        int f2 = sNum.top();
        sNum.pop();
        int f = 0;
        if (sTop == '+') {
            f = f1 + f2;
        } else if (sTop == '-') {
            f = f1 - f2;
        } else if (sTop == '*') {
            f = f1 * f2;
        } else if (sTop == '/') {
            f = f1 / f2;
        } else if (sTop == '^') {
            f = pow(f1, f2);
        }
        sNum.push(f);
    }
    std::cout << sNum.top() << std::endl;
    return 0;
}
行编辑内容
#include <iostream>
#include <stack>
#include <string>
#include <algorithm>

int main() {
    std::string inputStr;
    std::cin >> inputStr;
    std::stack<char> sk;
    for (int i = 0; i < inputStr.size(); i++) {
        // 退格键
        if (inputStr[i] == '#') {
            sk.pop();
        }
        else if (inputStr[i] == '@') {
            std::stack<char> skNew;
            sk = skNew;
        }
        else {
            sk.push(inputStr[i]);
        }
    }
    std::string strResult;
    while (!sk.empty()) {
        strResult.push_back(sk.top());
        sk.pop();
    }
    // 其实就是swap, ++first --last
    reverse(strResult.begin(), strResult.end());
    std::cout << strResult << std::endl;
    return 0;
}

队列

队列(queue)是可以表尾进行插入或表头删除操作的线性表,因此,对于队列来说,表尾端有其特殊含义,称为队头,相应的,表头端称为队尾,不含元素的队列称为空队列

队列有一个重要的性质,就是先进先出,First ln First Out(FIFO)。

构造代码(C)

和栈差不多,不做概述了

双端队列

除了传统的队列之外,还有一种数据结构叫做双端队列(deque),双端队列是限定插入和删除操作在表的两端进行的线性表

deque应用较少

循环队列

一般情况下,队列的两个指针front和rear分别指向队头和队尾,front=rear=0,因此,每当插入新的队列元素时,尾指针加1;每当删除某个元素,头指针加1

在队列中,头指针指向队头元素,尾指针指向队尾元素的下一个位置

当队头指针不断向后的过程中,这就导致队头前面的位置会空出来?浪费了空间,因此引入循环队列!

当新增元素进入的时候按照传统应该是front=rear队列满了(rear指向最后一个元素的下一个位置),但是还不够, 因为队列空的时候也是front=rear,所以无法判断是空是满!有两个处理方法:

  • 可以设置一个标志位判断队列是空是满,在循环队列中留一个元素的位置,一般在front的前面,当rear到达时说明是满的(当为空的时候rear=front,满的时候rear+1=front)
  • 另外设置一个标志位来标志是空是满
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值