栈、队列

简介: 预备知识:栈:   取出栈顶元素:S.top();              判断栈是否为空 :S.empty();           将元素x 添加 至栈:S.

预备知识:

栈:   取出栈顶元素:S.top();              判断栈是否为空 :S.empty();           将元素x 添加 至栈:S.push(x)

         弹出栈顶:S.pop();                    求栈存储元素的 个数 :S.size()

队列:判断队列是否为空 :Q.empty();  返回队列头部元素:Q.front();          返回队列尾部元素:Q.back()          弹出 队列头部元素:Q.pop();     将元素x 添加 至队列:Q.push(x);     求队列存储元素的个数 :Q.size()

LeetCode 255

一开始想把队列改写了,发现queue的源码是改了deque做的,deque的基础结构我懂,但是以我现在的技术来看,改起来还有点困难,所以就想到用两个队列来实现栈的功能。

以后有机会再写一个改了deque实现栈功能的版本吧,先打个码。

/*Implement the following operations of a stack using queues.

push(x) – Push element x onto stack.
pop() – Removes the element on top of the stack.
top() – Get the top element.
empty() – Return whether the stack is empty.

Notes:
You must use only standard operations of a queue 
– which means only push to back, peek/pop from front, size, and is empty operations are valid.
Depending on your language, queue may not be supported natively. 
You may simulate a queue by using a list or deque (double-ended queue), 
as long as you use only standard operations of a queue.
You may assume that all operations are valid (有效的)
(for example, no pop or top operations will be called on an empty stack).

队列的一些基本操作
push(x) 将x压入队列的末端
pop() 弹出队列的第一个元素(队顶元素),注意此函数并不返回任何值
front() 返回第一个元素(队顶元素)
back() 返回最后被压入的元素(队尾元素)
empty() 当队列为空时,返回true
size() 返回队列的长度
*/ 

#include "stdafx.h"
#include <iostream>
#include<queue>
using namespace std;

//创建两个队列对象(之前没写using namespace std,就一直说deque是未声明的标识符)
//一个用于存储当前信息,如果调用pop函数,则会用上另一个队列
queue<int>stack_model_one;
queue<int>stack_model_two;

//push(x) – Push element x onto stack.
void push(int m) {
	//找到当前栈
	//如果两个队列都为空,则存入第一个队列,此时应该是首次push
	if (stack_model_one.empty()&& stack_model_two.empty()) {
		stack_model_one.push(m);
		cout << "入栈成功" << endl;
	}
	//第一个队列为空,第二个队列不为空,此时当前栈是第二个队列
	else if (stack_model_one.empty() && !stack_model_two.empty()) {
		stack_model_two.push(m);
		cout << "入栈成功" << endl;
	}
	//第二个队列为空,第一个队列不为空,此时当前栈是第一个队列
	else if (stack_model_two.empty()&&!stack_model_one.empty()) {
		stack_model_one.push(m);
		cout << "入栈成功" << endl;
	}
	else {
		cout << "入栈失败" << endl;
	}
}

//pop() – Removes the element on top of the stack.
void pop( int length) {
	int p = 0;
	if (stack_model_one.empty() && stack_model_two.empty()) {		
		cout << "出栈失败" << endl;
	}
	//第一个队列为空,第二个队列不为空,此时当前栈是第二个队列
	else if (stack_model_one.empty() && !stack_model_two.empty()) {
		//将第二队列前length的元素赋值给队列一,然后将队列二制空
		for (int i = 0; i < length;i++) {
			stack_model_one.push(stack_model_two.front());
			stack_model_two.pop();
		}
		//删除队列二的最后一个元素
		stack_model_two.pop();
		cout << "出栈成功" << endl;
	}
	//第二个队列为空,第一个队列不为空,此时当前栈是第一个队列
	else if (stack_model_two.empty() && !stack_model_one.empty()) {	
		//将第一队列前length的元素赋值给队列二,然后将队列一制空
		for (int i = 0; i < length; i++) {
			stack_model_two.push(stack_model_one.front());
			stack_model_one.pop();
		}
		//删除队列一的最后一个元素
		stack_model_one.pop();
		cout << "出栈成功" << endl;
	}
	else {
		cout << "入栈失败" << endl;
	}
}

//top() – Get the top element.
void top() {
	if (stack_model_one.empty() && stack_model_two.empty()) {
		cout << "无栈顶元素" << endl;
	}
	//第一个队列为空,第二个队列不为空,此时当前栈是第二个队列
	else if (stack_model_one.empty() && !stack_model_two.empty()) {
		cout << "栈顶元素为:" << stack_model_two.back() << endl;
	}
	//第二个队列为空,第一个队列不为空,此时当前栈是第一个队列
	else if (stack_model_two.empty() && !stack_model_one.empty()) {
		cout << "栈顶元素为:" << stack_model_one.back() << endl;
	}
	else {
		cout << "栈顶元素获取失败" << endl;
	}
}

//empty() – Return whether the stack is empty.
void empty() {
	//如果两个队列都为空,则栈为空
	if (stack_model_one.empty() && stack_model_two.empty()) {
		cout << "当前为空栈" << endl;
	}
	else if (stack_model_one.empty() && !stack_model_two.empty()) {
		cout << "当前栈不为空" << endl;
	}
	else if (stack_model_two.empty() && !stack_model_one.empty()) {
		cout << "当前栈不为空" << endl;
	}
	else {
		cout << "栈是否为空判断失败" << endl;
	}
}

int main()
{
	
	cout << "push操作请输入“1”" << endl;
	cout << "pop操作请输入“2”" << endl;
	cout << "top操作请输入“3”" << endl;
	cout << "empty操作请输入“4”" << endl;

	//用于记录输入的操作序号
	int n = 0;
	//用于记录输入的值
	int m=0;
	//用于记录队列的长度
	int length = 0;
	while (1) {
		cin >> n;
		//输入你要运行的操作
		switch (n) {
		case 1:
			cout << "输入要插入的值" << endl;
			cin >> m;
			push( m);
			length++;
			break;
		case 2:
			//传入length-1,直接保留length长度的信息就好
			pop( length-1);
			length--;
			break;
		case 3:
			top ();
			break;
		case 4:
			empty();
			break;
		default:
			break;
		}
	}
    return 0;
}


老师讲解的方法:

使用队列实现栈——当push元素时,先将存储数据的队列中的元素存入临时队列,push之后再把临时队列中的元素push到存储数据的队列中。



使用栈实现队列——当push元素时,先将存储数据的栈中的元素存入临时栈中,push之后再把临时栈中的元素push到存储数据的栈中。



老师讲解的方法:

双栈法,即用两个栈 ,来实现队列的功能。一个栈为输入栈input_stack,一个栈为输出栈output_stack。

push操作时,将元素压入input_stack。pop操作时,当output_stack不为空时,直接弹出栈顶元素,为空,则将input_stack的元素全部压入output_stack中。  如此,时间复杂度只有O(1)

下面是自己实现的双栈法。

#include "stdafx.h"
#include<iostream>
#include<stack>
using namespace std;

//入队(无意中get了传递容器的技能,打个码MARK!!!!!!!!!!!!!!!!!!!)
void push(stack<int >&input_stack, int m) {
	input_stack.push(m);
	cout << "入队成功" << endl;
}

//出队
void pop(stack<int >&input_stack, stack<int >&output_stack) {
	//当output_stack为空
	if (output_stack.empty()) {
		//将input_stack元素全部压入output_stack
		while (!input_stack.empty()) {
			output_stack.push(input_stack.top());
			input_stack.pop();			
		}
		output_stack.pop();
		cout << "出队成功" << endl;
	}
	//当output_stack不为空
	else {
		output_stack.pop();
		cout << "出队成功" << endl;
	}
}
int main()
{
	stack<int>input_stack;
	stack<int>output_stack;
	char k='i';
	int n = 0, m = 0;

	cout<<"push操作请输入“1”"<<endl;
	cout << "pop操作请输入“2”" << endl;
	
	while (1) {		
		cin >> n;
		switch (n) {
		case 1:
			cout << "请输入要加入的元素" << endl;
			cin >> m;
			push(input_stack, m);
			break;
		case 2:
			pop(input_stack, output_stack);
			break;
		default:break;
		}		
	}
    return 0;
}



LeetCode 155


Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.

push(x) -- Push element x onto stack.
pop() -- Removes the element on top of the stack.
top() -- Get the top element.
getMin() -- Retrieve the minimum element in the stack.
Example:

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --> Returns -3.
minStack.pop();
minStack.top();      --> Returns 0.
minStack.getMin();   --> Returns -2.

model.h文件:改写了queue,写了一个实现要求功能的文件。时间复杂度是O(n),这个方法不是特别好。

#pragma once
#ifndef _STACK_
#define _STACK_
#include<iostream>
#include<queue>
using namespace std;

template<class T,class Sequence=queue<T>>
class Stack {
protected:
	Sequence c;
	Sequence d;
private:	
	int m;
public:
	//push(x) --Push element x onto stack.
	void push(int m) {		
		if (c.empty() && d.empty()) {
			c.push(m);
			cout << "入栈成功" << endl;
		}
		else if (!c.empty() && d.empty()) {
			c.push(m);
			cout << "入栈成功" << endl;
		}
		else if (c.empty() && !d.empty()) {
			d.push(m);
			cout << "入栈成功" << endl;
		}
		else {
			cout << "入栈失败,特殊原因" << endl;
		}		
	}
	//pop() --Removes the element on top of the stack.
	void pop() {
		if (c.empty() && d.empty()) {			
			cout << "出栈失败" << endl;
		}
		else if (!c.empty() && d.empty()) {
			c.pop();
			cout << "出栈成功" << endl;
		}
		else if (c.empty() && !d.empty()) {
			d.pop();
			cout << "出栈成功" << endl;
		}
		else {
			cout << "出栈失败,特殊原因" << endl;
		}
	}
	//top() --Get the top element.
	void top() {
		if (c.empty() && d.empty()) {
			cout << "获取栈顶元素失败" << endl;
		}
		else if (!c.empty() && d.empty()) {
			while (c.size() > 1) {
				d.push(c.front());
				c.pop();
			}
			//获取栈顶元素
			m=c.front();
			d.push(c.front());
			//排空c中的元素
			c.pop();
			cout << "栈顶元素为:" <<m<< endl;
		}
		else if (c.empty() && !d.empty()) {
			while (d.size() > 1) {
				c.push(d.front());
				d.pop();
			}
			//获取栈顶元素
			m = d.front();
			c.push(d.front());
			//排空c中的元素
			d.pop();
			cout << "栈顶元素为:" << m << endl;
		}
		else {
			cout << "获取栈顶元素失败,特殊原因" << endl;
		}
	}
	//getMin() --Retrieve the minimum element in the stack.
	void getMin() {
		if (c.empty() && d.empty()) {
			cout << "无最小元素" << endl;
		}
		else if (!c.empty() && d.empty()) {
			m = c.front();
			d.push(c.front());
			c.pop();
			while (c.size() > 0) {
				if (m > c.front()) {
					m = c.front();
				}
				d.push(c.front());
				c.pop();
			}
			cout << "最小元素是:" <<m<< endl;
		}
		else if (c.empty() && !d.empty()) {
			m = d.front();
			c.push(d.front());
			d.pop();
			while (d.size() > 0) {
				if (m > d.front()) {
					m = d.front();
				}
				c.push(d.front());
				d.pop();
			}
			cout << "最小元素是:" << m << endl;
		}
		else {
			cout << "获取最小元素失败,特殊原因" << endl;
		}
	}
};
#endif


.cpp文件,调用函数

#include "stdafx.h"
#include<iostream>
#include"model.h"
using namespace std;

int main()
{
	Stack<int> stack_model;
	int n=0,m = 0;
	cout << "push操作请输入“1”" << endl;
	cout << "pop操作请输入“2”" << endl;
	cout << "top操作请输入“3”" << endl;
	cout << "getMin操作请输入“4”" << endl;
	while (1) {
		cin >> n;
		switch (n) {
		case 1:
			cout<<"请输入要入栈的值"<<endl;
			cin >> m;
			stack_model.push(m);
			break;
		case 2:
			stack_model.pop();
			break;
		case 3:
			stack_model.top();
			break;
		case 4:
			stack_model.getMin();
			break;
		}
	}
    return 0;
}


老师讲解的方法: 时间复杂度是O(1)

设置两个栈, 数据栈data_stack 与 最小值栈min_stack ,这两个栈对于添加元素push与弹出栈
顶元素pop都是 同步进行 的:
1.push(x) : 将元素x直接压入数据栈data_stack中,若x小于最小值栈栈顶,则将 x 压入 最小值栈中,否则将 最小值栈栈顶压入最小值栈。
2.pop() :  同时弹出( 移除) 数据栈栈顶与最小值栈顶元素。
3.top() : 返回 数据栈data_stack 栈顶元素。
4.getMin() : 返回 最小值栈min_stack 栈顶元素。




POJ 1363

/*
题目大意:

已知火车要从A入站,然后从C出站。火车进站的顺序为1~N,现在给你出站的顺序。
问:能不能通过站台改变火车出站顺序来实现按所给顺序出站。

解题思路:

把站台看做是一个栈,按1~N的顺序遍历火车原先顺序,先入栈,
如果栈顶的火车编号和所给出站顺序将要出站的编号一样。
那么火车就出栈,直到栈里边所有满足出站顺序的火车都出站,否则就一直入栈。
最后判断所有火车是否都出站了。若都出站,输出Yes,否则输出No。
*/ 

#include"stdafx.h"
#include<iostream>
#include<stack>
using namespace std;

int main()
{
	cout << "请输入要输入的元素个数" << endl;
	int m = 0, temp = 0;

	while (cin >> m) {
		//创建一个数组,用于存储输入的数字串
		int *array;
		array = (int *)malloc(sizeof(int)*m);
		stack<int>stack_model;

		cout << "请输入需要判断的数字串" << endl;
		//将输入的数字串存入数组
		for (int i = 0; i < m; i++) {
			cin >> temp;
			array[i] = temp;
		}

		//对比元素,值在1~m之间
		int flag = 1;
		for (int i = 0; i < m; i++) {
			//当前值小于等于输入的数字串中需要对比的值时,入栈
			while (flag <= array[i]) {
				stack_model.push(flag);
				flag++;
			}
			//此时栈顶元素等于array[i]
			int cur = stack_model.top();
			//如果输入的数字串符合栈,则一共会弹出m次
			stack_model.pop();
			if (cur != array[i]) {
				cout<<"数字串不是栈顺序"<<endl;
				break;
			}
		}
		if (stack_model.size() == 0) {
			cout<<"数字串是栈顺序"<<endl;
		}
	}
	return 0;
}

上面自己写的算法的时间复杂度太大,需要修改。


老师讲解的方法:

同时使用一个队列与一个栈来解决该问题

设队列order与栈为S。队列order存储待判断是否合法的出栈序列 ,使用栈S用来模拟出栈与入栈的过程。

按照1-n的顺序,将元素 push 进入栈S 中:每push一个元素,即检查栈顶 S.top()是否与队列头部元素order.front()相同。

如果相同则同时弹出栈顶元素与队列头部元素, 直到栈空或栈顶与队列头部元素不同 。

若最终栈为空 ,则说明序列合法 ,否则不合法。


预备知识:堆

我们一般使用二叉堆来实现优先级队列 ,它的内部调整算法复杂度为log(N), 标准STL 的优先级队列包括如下5 种操作,设堆H:

1.取出堆顶元素:H.top();           2.判断堆是否为空 :H.empty();           3.将元素x添加 至堆:H.push(x)

4. 弹出堆顶:H.pop();                5.求堆存储元素的个数 :H.size()


优先队列根据权值,将入队元素进行排序。只允许一端入队另一端出队。底层容器是vector。


LeetCode 215


思路:快排的时间复杂度是nlogn。感觉这题不是中等难度的题,是easy题。

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        sort(nums.begin(),nums.end());
        int temp=0;
        temp=nums.size()-k;
        return nums[temp];
    }
};


方法二,优先队列




LeetCode 295


方法:动态维护一个 最大堆 与一个 最小堆 ,最大堆存储一半数据,最小堆存储

一半数据, 维持 最大堆的堆顶比最小堆的堆顶小,即可解决该问题。


相关文章
|
1月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
150 77
|
13天前
|
DataX
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。
|
1月前
|
存储 C++ 索引
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
50 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
|
1月前
|
存储 C语言 C++
【C++数据结构——栈与队列】链栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现链栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储整数,最大
49 9
|
1月前
|
C++
【C++数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】(1)遇到左括号:进栈Push()(2)遇到右括号:若栈顶元素为左括号,则出栈Pop();否则返回false。(3)当遍历表达式结束,且栈为空时,则返回true,否则返回false。本关任务:编写一个程序利用栈判断左、右圆括号是否配对。为了完成本关任务,你需要掌握:栈对括号的处理。(1)遇到左括号:进栈Push()开始你的任务吧,祝你成功!测试输入:(()))
43 7
|
3月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
103 5
|
3月前
|
算法
数据结构之购物车系统(链表和栈)
本文介绍了基于链表和栈的购物车系统的设计与实现。该系统通过命令行界面提供商品管理、购物车查看、结算等功能,支持用户便捷地管理购物清单。核心代码定义了商品、购物车商品节点和购物车的数据结构,并实现了添加、删除商品、查看购物车内容及结算等操作。算法分析显示,系统在处理小规模购物车时表现良好,但在大规模购物车操作下可能存在性能瓶颈。
75 0
|
3月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
364 9
|
3月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
58 1
|
3月前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
124 21