栈与队列
(一)、栈
1.栈的定义(Stack):
栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。(先进后出)
2.栈链式储存结构的进栈出栈
链式栈的基本思路:是把添加的元素直接放在链表的第一个节点。出栈的时候也是直接把第一个节点进行出栈
设置链表:
public class Node {
Node next;
T item;
public Node(T item, Node next) {
this.item = item;
this.next = next;
}
}
压栈:(压栈压的是头节点的下一个结点)
public void push(T t) {
Node Insert = new Node(t, null);
if (this.size == 0) {
this.head.next = Insert;
} else {
//获取原先的第一个结点
Node before = this.head.next;
//开始进行链接
this.head.next = Insert;
Insert.next = before;
}
this.size++;
}
出栈:(不用this.size-- 操作)
public T pop() { //出栈的话不用--
//获取第一个结点
Node first = this.head.next;
if (this.size == 1) {
return first.item;
} else {
//获取第二个结点
Node second = first.next;
//开始断链
this.head.next = second;
//进行数量控制:
return first.item;
}
}
类方法:
public class LinkeStack<T> {
public class Node {
Node next;
T item;
public Node(T item, Node next) {
this.item = item;
this.next = next;
}
}
Node head;
int size;
public LinkeStack() {
this.size = 0;
this.head = new Node(null, null);
}
//获取个数
public int getSize() {
return this.size;
}
//进行压栈操作(实际上就是直接压入头节点的下一个结点)
public void push(T t) {
Node Insert = new Node(t, null);
if (this.size == 0) {
this.head.next = Insert;
} else {
//获取原先的第一个结点
Node before = this.head.next;
//开始进行链接
this.head.next = Insert;
Insert.next = before;
}
this.size++;
}
//进行出栈的操作:
public T pop() { //出栈的话不用--
//获取第一个结点
Node first = this.head.next;
if (this.size == 1) {
return first.item;
} else {
//获取第二个结点
Node second = first.next;
//开始断链
this.head.next = second;
//进行数量控制:
return first.item;
}
}
}
3.栈顺序储存结构的出栈和进栈
类方法:(继承了顺序表的函数)
import java.util.ArrayList;
public class SquenceStack<T> extends SquenceLisr {
public SquenceStack(int capacity){
super(capacity);
}
//进行入栈
public void push(T t){
Insert(t);
}
//进行出栈
public T pop(){
return (T)remove(getLength()-1);
}
}
主方法:
import java.sql.SQLOutput;
import java.util.*;
import java.awt.*;
import java.lang.Math;
public class hello {
public static void main(String []avgs) {
SquenceStack<String> stack=new SquenceStack<>(10);
stack.push("aa");
stack.push("bb");
stack.push("cc");
stack.push("dd");
for(int i=0;i<4;i++){
System.out.println(stack.pop());
}
}
}
4.栈的实践操作(计算器)
4.1基础操作(两数相加)
import java.sql.SQLOutput;
import java.util.*;
import java.awt.*;
import java.lang.Math;
public class hello {
public static void main(String[] avgs) {
//设置表达式
String express="7)8";
//进行分步取解
//获取数字1;
char numStr1=express.charAt(0);
//获取第二个数字:
char numStr2=express.charAt(2);
//获取中间的字符
char operation=express.charAt(1);
//进行字符串的转换
int num1=Integer.parseInt(numStr1+""); //只能转换字符串,所以这样做
int num2=Integer.parseInt(numStr2+"");
try {
int reuult= Caluat(num1,num2,operation);
System.out.println(reuult);
} catch (Exception e) {
System.out.println("输入的符号有错");
}
}
public static int Caluat(int num1,int num2,char operation){
switch(operation){
case '+':
return num1+num2;
case '-':
return num1-num2;
case '*':
return num1*num2;
case '/':
return num1/num2;
default:
return -0;
}
}
}
4.2进阶操作(10以内的,多数相加)
基本思路:创建两个栈、一个是数字栈、另一个是字符栈。然后通过对字符串的遍历得到对应的字符,然后通过判断字符,如果是逻辑表达式,那么就进入字符栈,如果是数字字符,那么就进入数字栈。然后再进行对最后进入的三个字符进行依次出栈,得到结果后,再进行入栈操作。直到最后字符栈为空就最后一次数字出栈。
import java.sql.SQLOutput;
import java.util.*;
import java.awt.*;
import java.lang.Math;
public class hello {
public static void main(String[] avgs) {
String express="1+2+3+5";
//设置数字栈
Stack<Integer> nums=new Stack<>();
//设置字符栈
Stack<Character> operation=new Stack();
//进行压栈操作:
for(int i=0;i<express.length();i++) {
char ch=express.charAt(i);
if (Judge(ch)){ //压入符号栈
operation.push(ch);
}else{ //压入数字栈
nums.push(Integer.parseInt(ch+""));
}
}
//进行出栈的操作
while (!operation.empty()) {
int num1=nums.pop(); //出栈数字1
int num2=nums.pop(); //出栈数字2
char operation1=operation.pop(); //出栈字符
nums.push(Caluat(num1,num2, operation1)); //得出结果再入栈
}
System.out.println(nums.pop());
}
public static boolean Judge(char ch){
return ch=='+'||ch=='-'||ch=='*'||ch=='/';
}
public static int Caluat(int num1,int num2,char operation){
switch(operation){
case '+':
return num1+num2;
case '-':
return num1-num2;
case '*':
return num1*num2;
case '/':
return num1/num2;
default:
return -0;
}
}
}
4.3进阶操作(10以内的±/*)
基本思路:
首先在2的基础上添加一个操作,在操作运算符的时候。进行判断加入话:优先级高的话,那么就直接在添加运算的时候就进行出栈和入栈的操作。然后继续正常操作。
peek(),进行查看前一个栈顶元素.
import java.sql.SQLOutput;
import java.util.*;
import java.awt.*;
import java.lang.Math;
public class hello {
public static void main(String[] avgs) {
String express="2*2/3*5+6";
//设置数字栈
Stack<Integer> nums=new Stack<>();
//设置字符栈
Stack<Character> operation=new Stack();
//进行压栈操作:
for(int i=0;i<express.length();i++) {
char ch=express.charAt(i);
if (Judge(ch)){ //压入符号栈
if(operation.empty()){
operation.push(ch);}else{
char c=operation.peek(); //获取已经插入栈顶的符号,但是不是出栈
if(Grade(ch)<=Grade(c)) { //假如说栈顶的优先级低于栈底
char operation4=operation.pop(); //那么取出栈顶元素(并不是待插入的栈顶元素)
int num3 = nums.pop();
int num4 = nums.pop();
//得出结果
int result = Caluat(num4, num3, operation4);
//把结果进行压栈操作
nums.push(result);
}operation.push(ch);
}
}else{ //压入数字栈
nums.push(Integer.parseInt(ch+""));
}
}
//进行出栈的操作
while (!operation.empty()) {
int num1=nums.pop(); //出栈数字1
int num2=nums.pop(); //出栈数字2
char operation1=operation.pop(); //出栈字符
nums.push(Caluat(num2,num1, operation1)); //得出结果再入栈
}
System.out.println(nums.pop());
}
public static boolean Judge(char ch){
return ch=='+'||ch=='-'||ch=='*'||ch=='/';
}
public static int Caluat(int num1,int num2,char operation){
switch(operation){
case '+':
return num1+num2;
case '-':
return num1-num2;
case '*':
return num1*num2;
case '/':
return num1/num2;
default:
return -0;
}
}
public static int Grade(char ch){
if(ch=='+'||ch=='-')return 1;
else if (ch=='*'||ch=='/')return 2;
else return 0;
}
}
(二)、队列
1.队列的定义:
队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。(前端(队尾)删除 后端(队头)插入).------(先进先出)
2.顺序队列
基本思路:头标和尾标初始位置都为0,每次插入一个元素的时候尾标就会后移一格,删除一个元素的时候就会后移一格。
类文件:
public class Front <T>{
//定义队列数组
T [] elem;
//定义头部游标
int head;
//定义尾部游标:
int tail;
//定义队列的长度:
int size;
//定义队列的容量:
int capctity;
//进行初始化:
public Front(int capctity){
this.elem=(T[])new Object[capctity];
this.size=0;
//初始化游标的位置
this.head=0;
this.tail=0;
}
//进行入队列的操作
public boolean offer(T item){
//直接把添加的元素放在队尾的位置
elem[this.tail]=item;
this.tail++; //当插入的之后尾下标需要后移
this.size++;
if(this.tail==capctity){return false;}
return true;
}
//进行出队的操作:
public T leave(){
if(this.size==0){return null;}
T item=elem[this.head];
this.size--;
this.head++; //当删除的时候头部下标会后裔
return item;
} public int size(){
return this.size;
}
}
测试类:
import java.sql.SQLOutput;
import java.util.*;
import java.awt.*;
import java.lang.Math;
public class hello {
public static void main(String[] avgs) {
Front<String> s=new Front<>(10);
s.offer("aa");
s.offer("bb");
s.offer("cc");
while (s.size()>0) { //因为这里是出队,出队之后个数会减少。并不是顺序表中的遍历
System.out.println(s.leave());
}
}
}
3.线性队列:
基本思路:头指针和尾指针,初始化是在第一个结点,并不是头节点。插入元素的时候,插入的位置是尾标的下一位。插入之后需要把尾标移动到新插入的元素下面。在出队的时候,
JavaBean类:
public class Front <T>{
class Node{
Node next;
T item;
public Node(T item,Node next){
this.item=item;
this.next=next;
}
}
Node head;
int size;
Node tail;
public Front(){
this.size=0;
}
public boolean offer(T t){
Node node=new Node(t,null);
if(size==0){ //假如说是第一个
this.tail=node; //在这初始化
this.head=node;
}else {
this.tail.next = node; //尾标的后一个添加
this.tail=node; //然后把尾标指向添加的这个位置
}
this.size++;
return true;
}
public T leave(){
if(this.head==null){ //假如说没有了
throw new RuntimeException("没有元素了");
}
Node node=this.head;
//移动头坐标到下一位
this.head=this.head.next;
if(node.next==null){ //假如说node 后面没有了
this.tail=null;
}
this.size--;
return node.item;
}
}
测试类:
import java.sql.SQLOutput;
import java.util.*;
import java.awt.*;
import java.lang.Math;
public class hello {
public static void main(String[] avgs) {
Front<String> s=new Front<>();
s.offer("aa");
s.offer("bb");
s.offer("cc");
while (s.size>0){
System.out.println(s.leave());
}
}
}
4.循环队列:
基本思路:当添加的受taill后移,取出的时候head后移。然后0和1的位置被控出来了。然后通过借助0和1的位置进行添加元素。
JavaBean类
public class Dui <T>{
T []elem;
int size;
int head;
int tail;
int capitcy;
public Dui(int capitcy){
elem=(T[])new Object[capitcy]; //千万不能写this.
this.head=0;
this.size=0;
this.tail=0;
this.capitcy=capitcy;
}
public boolean add(T t){
if(this.size==this.capitcy){
throw new RuntimeException("循环队列已满");
}
//添加元素
elem[this.tail]=t;
this.tail++;
//取模求循环后的个数,当取出来的时候就空出来了
this.tail=this.tail%this.capitcy;
this.size++;
return true;
}
//进行出队
public T remove(){
if(this.size==0){
throw new RuntimeException("队列中已经没有元素了");
}
T s=elem[this.head];
this.head++;
this.head=this.head%this.capitcy;
this.size--;
return s;
}
}
主类:
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.sql.SQLOutput;
import java.util.*;
import java.awt.*;
import java.lang.Math;
public class hello {
public static void main(String[] avgs) {
Dui<String> s=new Dui<>(3);
s.add("aa");
s.add("bb");
s.add("cc");
while(s.size>0){
System.out.println(s.remove());
}
s.add("dd");
System.out.println(s.remove());
}
}