数据结构----结构–线性结构–栈,队列
一.栈:Stack
1.栈的特点:
先进后出:FILO(对一组数据有倒叙要求时可以用栈)
2.栈的实现
顺序存储:数组实现:
缺点:空间大小受限
链式存储:链表实现
3.栈的基本函数(这里是一部分)
1.Init
2.Push
3.Pop
4.Clear
5.Destory
6.Count
7.IsEmpty
创建栈,并实现Push,Pop这两个函数
代码如下
//c语言
#include <stdio.h>
#include <stdlib.h>
typedef struct Node { int m_value;struct Node* m_pNext;}PNode;PNode* creatStack() {//创建栈PNode* stackTop = NULL;//栈顶return stackTop;
}
void creatStackNode(int x, PNode** stackTop) {//创建栈中的元素PNode* Temp = (PNode*)malloc(sizeof(PNode));Temp->m_value = x;Temp->m_pNext = NULL;//添加元素Temp->m_pNext = *stackTop;*stackTop = Temp;
}void stackpush(int x, PNode** stackTop) {//往栈里添加元素creatStackNode(x, stackTop);//创建元素,并添加元素
}void stackpop(PNode** stackTop) {//出栈if (stackTop == NULL) return;PNode* Temp = *stackTop;printf("%d\n", Temp->m_value);//输出该元素的值*stackTop = (*stackTop)->m_pNext;free(Temp);//释放空间
}int main() {PNode* stackTop = creatStack();//获得一个栈,此时是空栈stackpush(3, &stackTop);//添加元素stackpush(6, &stackTop);stackpush(7, &stackTop);stackpop(&stackTop);//弹出元素stackpop(&stackTop);stackpop(&stackTop);return 0;
}
进行所有函数的实现(对上面代码进行一些改动)
代码如下
//c语言
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {int m_value;struct Node* m_pNext;}PNode;typedef struct Top {PNode* p_Top;int count;
}PTop;PTop* Init() {//创建PTop* p1 = (PTop*)malloc(sizeof(Top));p1->p_Top = NULL;p1->count = 0;return p1;
}
void creatStackNode(int x, PTop* P_Top) {//创建栈中的元素if (P_Top == NULL) {printf("栈不存在\n");exit(1);}PNode* Temp = (PNode*)malloc(sizeof(PNode));Temp->m_value = x;Temp->m_pNext = NULL;//添加元素printf("入栈元素的值为%d\n", Temp->m_value);Temp->m_pNext = P_Top->p_Top;P_Top->p_Top = Temp;P_Top->count += 1;
}void stackpush(int x, PTop* P_Top) {//往栈里添加元素creatStackNode(x, P_Top);//创建元素,并添加元素
}void stackpop(PTop* P_Top) {//出栈if (P_Top->p_Top == NULL) return;PNode* Temp = P_Top->p_Top;printf("出栈元素的值为%d\n", Temp->m_value);//输出该元素的值P_Top->p_Top = (P_Top->p_Top)->m_pNext;P_Top->count -= 1;free(Temp);//释放空间
}void clear(PTop* P_Top) {//清空栈if (P_Top->count == 0) {printf("无链表\n");}while (P_Top->p_Top != NULL) {stackpop(P_Top);}printf("链表已被清空\n");
}void Count(PTop* P_Top) {//看栈中的元素有几个printf("栈中的元素有%d个\n",P_Top->count);
}int IsEmpty(PTop* P_Top) {//判断是否为空if (P_Top->count) {printf("不为空 返回\n");return 1;}else {printf("为空 返回\n");return 0;}
}
void GetTop(PTop* P_Top) {printf("栈顶元素为");printf("%d\n",(*P_Top->p_Top).m_value);
}void Destory(PTop** P_Top) {if (P_Top == NULL) {printf("无栈");}clear(*P_Top);printf("栈顶已被回收\n");delete *P_Top;*P_Top = NULL;
}
int main() {PTop* P_Top = Init();//获得栈顶stackpush(3, P_Top);//添加元素stackpush(6, P_Top);GetTop(P_Top);Count(P_Top);stackpush(7, P_Top);Destory(&P_Top);//stackpop(&P_Top);//弹出元素//stackpop(&P_Top);//stackpop(&P_Top);stackpush(3, P_Top);return 0;
}
4.可用栈的题目
第一题
题目:一万个括号 ‘(’ ‘)’,判断这些括号是否完全匹配
解决
方法一:
1.循环,如果是左括号就入栈
2.如果是右括号将栈顶的元素出栈,如果栈中无元素,就是不匹配,右括号无对应的左括号
3.当括号都处理完了,那么循环结束,可以判断完全匹配
方法二:
循环,左半括号记为加1,右半括号记为-1,当总和小于0时就是不匹配
当括号都处理完了,那么循环结束,可以判断完全匹配
第二题(网址为https://leetcode.cn/problems/valid-parentheses/)
题目:给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串 s
,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
解决
1.循环,如果是左括号就入栈
2.如果是右括号将栈顶的元素出栈,并根据出栈的括号类型进行判断,如果栈中无元素,就是不匹配,右括号无对应的左括号
3.当括号都处理完了,那么循环结束,可以判断完全匹配
代码如下
//这里的代码是c++语言下的
class Solution {
public:bool isValid(string s) {stack<char> sta;//创建一个栈const char* temp=s.c_str();//遍历字符串的变量while(*temp!='\0'){//遍历if(*temp=='('||*temp=='{'||*temp=='['){//如果字符为左括号就入栈sta.push(*temp);}else{if(sta.empty()){//如果有右括号,没有左括号了,不闭合,失败return false;}if(sta.top()=='('){//右括号与左括号不匹配,不闭合,失败if(*temp!=')'){return false;}}else if(sta.top()=='{'){if(*temp!='}'){return false;}}else if(sta.top()=='['){if(*temp!=']'){return false;}}sta.pop(); }temp+=1;}if(!sta.empty()){return false;}return true;}
};
5.递归时间复杂度的计算
主方法求解递归式:T(n)=aT(n/b)+f(n) (n代表要处理数据的规模,T代表处理这个数据规模的时间消耗,a时子问题的个数,b分之n代表当前子问题处理的数据规模式原有数据量的几分之几,f(n)时除了递归以外要做的事情所用的时间消耗)
计算:比较nlogb的a次方和f(n),谁大谁就是递归的时间复杂度
一样大的话,nlogb的a次方乘以log2的n次方就是递归的时间复杂度
6.计算器运算(应用栈)
1.中缀表达式(简称为表达式)
2.后缀表达式
3.中缀转后缀:
1.借助辅助线
2.遇到数字或字母,直接输出
3.遇到符号,将当前符号与栈顶元素进行优先级比较
(1)当前符号优先级高,入栈
(2)当前符号优先级没有栈顶符号优先级高,栈内元素依次出栈,直到比当前元素优先级低为止,再将当前元素入栈
4.遇到“(”无条件入栈,遇到")“栈内元素依次出栈,直到”)"停止
快速转换:把每个运算式都加上括号,括号里的运算符号都移到右括号外
4.后缀转前缀:
1.借助辅助栈
2.遇到数字或字母直接入栈
3.遇到符号,将栈顶元素的下一个和栈顶元素构成表达式
二.队列:queue
1.队列的特点:
先进先出:FIFO
2.队列的实现
顺序存储:数组实现:
缺点:空间大小受限
日和实现循环队列:进行取余 取余的是数组的长度
链式存储:链表实现
3.队列的基本函数(这里是一部分)
1.Init
2.Push
3.Pop
4.front
5.empty
将这里所有的函数功能进行实现
代码如下
#include <stdio.h>
#include<stdlib.h>
typedef struct node {int m_value;struct node* m_next;
}NODE;typedef struct node2 {int count;NODE* m_head;NODE* m_tail;
}P_POINT;//队列初始化
void init(P_POINT** point) {*point = (P_POINT*)malloc(sizeof(P_POINT));(*point)->count = 0;(*point)->m_head = NULL;(*point)->m_tail = NULL;
}//添加元素
void Push(P_POINT* point,int x) {if (point == NULL) return;NODE* Temp = (NODE*)malloc(sizeof(NODE));//创造节点Temp->m_value = x;//初始化Temp->m_next = NULL;if (point->m_head == NULL) {//头节点如果为空point->m_head = Temp;point->m_tail = Temp;printf("添加的元素为%d\n", Temp->m_value);}else {//头节点不为空point->m_tail->m_next = Temp;point->m_tail = Temp;printf("添加的元素为%d\n", Temp->m_value);}point->count += 1;
}//删除队头
void pop(P_POINT* point) {if (point == NULL) return;if (point->count == 0) return;NODE* Temp = point->m_head;point->m_head = point->m_head->m_next;printf("删除的元素为%d\n", Temp->m_value);free(Temp);point->count -= 1;if (point->count == 0) {point->m_tail = NULL;}
}//获得队头
void GetFront(P_POINT* point) {printf("队首为%d\n", point->m_head->m_value);
}//获得队列长度
void GetCount(P_POINT* point) {printf("获得队列的长度为%d\n",point->count);
}//判断队列是否为空
void IsEmpty(P_POINT* point) {if (point->count != 0) {printf("队列不为空\n");}else {printf("队列为空\n");}
}int main() {P_POINT* point = NULL;init(&point);//队列初始化Push(point, 5);//放入元素Push(point, 7);Push(point, 8);GetCount(point);//得到队列中元素的个数Push(point, 1);GetFront(point);//得到队头元素pop(point);//删除队列中的元素pop(point);pop(point);IsEmpty(point);//kreturn 0;
}
三.两个栈实现队列
实现:
1.第一个栈进行入队,第二个栈进行出队
2.当进行入队时,如果第二个栈中有元素,将第二个栈中的元素出栈并添加到第一个栈中,在第一个栈中添加新的元素
3.当进行出队时,如果第一个栈中有元素,将第一个栈中的元素出栈并添加到第二个栈中,在第二个栈中进行弹出操作
两个栈实现队列的题(网址为https://leetcode.cn/problems/yong-liang-ge-zhan-shi-xian-dui-lie-lcof/)
题目:
用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail
和 deleteHead
,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead
操作返回 -1 )
代码如下:
//这里的代码是c++语言下的
class CQueue {
public:CQueue() {}stack<int> sta1;stack<int> sta2;void appendTail(int value) {//添加元素while(!sta2.empty()){int temp=sta2.top();sta1.push(temp);sta2.pop();}sta1.push(value);}int deleteHead() {//删除元素while(!sta1.empty()){int temp=sta1.top();sta2.push(temp);sta1.pop();}if(sta2.empty()){return -1;}int temp2=sta2.top();sta2.pop();return temp2;}
};
四.两个队列实现栈
实现:
1.入栈:新元素添加到非空的队列中(第一次两个队列都为空,添加到哪个里面都可以)
2.出栈:将非空的队列中的元素除尾元素外都添加到另一个空队列里,然后将尾部的那个元素删除
用两个队列实现栈的题(网址为https://leetcode.cn/problems/implement-stack-using-queues/)
题目:
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push
、top
、pop
和 empty
)。
实现 MyStack
类:
void push(int x)
将元素 x 压入栈顶。int pop()
移除并返回栈顶元素。int top()
返回栈顶元素。boolean empty()
如果栈是空的,返回true
;否则,返回false
。
注意:
- 你只能使用队列的基本操作 —— 也就是
push to back
、peek/pop from front
、size
和is empty
这些操作。 - 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
代码如下:
//这里的代码是c++语言下的
class MyStack {
public:MyStack() {}queue<int> q1;queue<int> q2;int bool1=1;void push(int x) {//添加元素if(bool1){q1.push(x);bool1=0;}else{if(!q1.empty()){q1.push(x);}else{q2.push(x);}}}int pop() {//移除并返回移除元素int temp=0;if(!q1.empty()){while(q1.size()>1){q2.push(q1.front());q1.pop();}temp=q1.front();q1.pop();}else{while(q2.size()>1){q1.push(q2.front());q2.pop();}temp=q2.front();q2.pop();}return temp; }int top() {//获得栈顶元素int temp=0;if(!q1.empty()){while(q1.size()>1){q2.push(q1.front());q1.pop();}temp=q1.front();q2.push(q1.front());q1.pop();}else{while(q2.size()>1){q1.push(q2.front());q2.pop();}temp=q2.front();q1.push(q2.front());q2.pop();}return temp;}bool empty() {if(q1.empty()&&q2.empty()){return true;}return false;}
};/*** Your MyStack object will be instantiated and called as such:* MyStack* obj = new MyStack();* obj->push(x);* int param_2 = obj->pop();* int param_3 = obj->top();* bool param_4 = obj->empty();*/