数据结构——栈和队列(模拟实现)
目录
一:栈
1.1: 概念
1.2 :栈的使用
1.3:栈的模拟实现
二:队列
2.1:概念
2.2: 队列的使用
2.3:队列的模拟实现(使用链表)
2.4:循环队列
一:栈
1.1: 概念
栈:⼀种特殊的线性表,其只允许在固定的⼀端进⾏插⼊和删除元素操作。进⾏数据插⼊和删除操作的⼀端称为栈顶,另⼀端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。(特殊的线性表)
压栈:栈的插⼊操作叫做进栈/压栈/⼊栈,⼊数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据在栈顶。
本质上就是顺序表/链表,但是是在顺序表/链表的基础上,做出限制:
对栈来说,禁止对顺序表/链表的各种增删改查,只支持三个操作:入栈、出栈、取栈顶元素。
1.2 :栈的使用
接下来我们实现一下: package stack; import java.util.Stack; public class Tets1 { public static void main(String[] args) { //使用标准库的栈 Stack<String> stack = new Stack<>(); //入栈 stack.push("hello"); stack.push("world"); stack.push("!"); //取栈顶元素、peek就是查看元素但不出栈 //peek()方法返回栈顶元素,但不删除它 String top=stack.peek(); System.out.println(top);//! //出栈(先进后出) String s=stack.pop(); System.out.println(s);//! s=stack.pop(); System.out.println(s);//world s=stack.pop(); System.out.println(s);//hello } }
如果栈为空 peek 和pop就会报错
1.3:栈的模拟实现
每个方法都有注释:
package stack; import java.util.Arrays; import java.util.EmptyStackException; //模拟实现栈 public class MyStack { private String[] stack; private int size; public MyStack() { stack = new String[1]; size = 0; } public MyStack(int capacity) { stack = new String[capacity]; size = 0; } //扩容 private void resize(){ //创建一个更长的数组 String[] newStack = new String[stack.length*3]; //将原数组中的元素复制到新数组中 for(int i=0;i<stack.length;i++){ newStack[i] = stack[i]; } //更新栈的引用 stack=newStack; } //入栈 public void push(String item){ if(size==stack.length){ //kronlei:扩容 resize(); } stack[size++] = item; } //出栈 public String pop(){ if(size==0){ throw new EmptyStackException(); } String item = stack[size-1]; //缩容 size--; return item; } //获取栈顶元素 public String peek(){ if(size==0){ throw new EmptyStackException(); } // 直接取最后一个元素 return stack[size-1]; } @Override public String toString() { return "MyStack{" + "stack=" + Arrays.toString(stack) + ", size=" + size + '}'; } public static void main(String[] args) { MyStack stack = new MyStack(); stack.push("a"); stack.push("b"); stack.push("c"); System.out.println(stack.toString());//MyStack{stack=[a, b, c], size=3} System.out.println(stack.peek());//c System.out.println(stack.pop());//c } }
二:队列
2.1:概念
队列:只允许在⼀端进⾏插⼊数据操作,在另⼀端进⾏删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)⼊队列:进⾏插⼊操作的⼀端称为队尾(Tail/Rear)出队列:进⾏删除操作的⼀端称为队头(Head/Front)
队列这样的数据结构,往往针对“耗时比较长”的操作提供辅助工作
有些操作没办法一口气全部处理完,按照顺序一个一个来,为了确保处理的顺序不乱,就把待处理的数据放到队列中。
2.2: 队列的使用
注意:Queue是个接⼝,在实例化时必须实例化LinkedList的对象,因为LinkedList实现了Queue接⼝。 package queue; import java.util.LinkedList; import java.util.Queue; public class Test { public static void main(String[] args) { Queue<Integer> queue = new LinkedList<>(); queue.offer(1); queue.offer(2); queue.offer(3); queue.offer(4); queue.offer(5); System.out.println("Queue: " + queue); System.out.println("Queuefist: " + queue.peek()); queue.poll(); System.out.println("Queue: " + queue); //判定队列是否为空 if(queue.peek()==null)} }
2.3:队列的模拟实现(使用链表)
每个方法斗鱼注释,如果有不明白的小伙伴可以评论区奥
package queue; //基于单链表实现队列 public class MyQueue { static class Node { public String val; public Node next; public Node(String val) { this.val = val; this.next = null; } } private Node head = null; private Node tail = null; //基于链表实现队列 //入队-》尾插 public void offer(String val) { Node newNode = new Node(val); if(head==null){ head=tail=newNode; return ; }else{ tail.next=newNode; //尾插之后,更新tail tail=newNode; } } //出队-》头删 public String poll() { if(head==null){ return null; } //保存头节点的值 //接下来把这个值删掉,需要返回这个值 String val=head.val; head=head.next; if(head==null){ //如果头节点已经是最后一个节点,则更新tail tail=null; } return val; } //查看队首元素 public String peek() { if(head==null){ return null; }else{ //直接返回头节点的值 return head.val; } } public boolean isEmpty(){ return head==null; } public int size() { int size=0; for(Node cur=head;cur!=null;cur=cur.next){ size++; } return size; } public static void main(String[] args) { MyQueue queue=new MyQueue(); queue.offer("a"); queue.offer("b"); queue.offer("c"); System.out.println(queue.peek());//查看队首元素 System.out.println(queue.poll());//出队 System.out.println(queue.peek());//查看队首元素 System.out.println(queue.poll());//出队 System.out.println(queue.peek());//查看队首元素 System.out.println(queue.poll());//出队 System.out.println(queue.peek());//查看队首元素 System.out.println(queue.isEmpty());//判断是否为空 } }
2.4:循环队列
实际中我们有时还会使⽤⼀种队列叫循环队列。如操作系统课程讲解⽣产者消费者模型时可以就会使⽤循环队列。环形队列通常使⽤数组实现这个我们就使用数组表达,有一个head和tail(头和尾),每次加入元素或者出队列。就可以加加减减,然后创建一个size表示元素个数,如果size==0,那就空了。具体看看代码:
package queue; public class MyQueueByArray { //数组实现队列 public String[] arr=null; //队首 public int head=0; //队尾 public int tail=0; //元素个数 public int size=0; public MyQueueByArray(){ arr=new String[10000]; } public MyQueueByArray(int capacity){ arr=new String[capacity]; } //入队列 public void offer(String val){ if (size==arr.length){ return ; }else{ //把新的元素放到tail位置 arr[tail]=val; //tail后移 tail++; //为构成环形队列,当tail==arr.length时,重新回到0 if(tail==arr.length){ tail=0; } //元素个数+1 size++; } } //出队列 public String poll() { if (size == 0) { return null; } //取队首元素 String value = arr[head]; //head后移 head++; //为构成环形队列,当head==arr.length时,重新回到0 if (head == arr.length) { head = 0; } //更新元素个数 size--; return value; } //查看队首元素 public String peek(){ if(size==0){ return null; } return arr[head]; } //判断队列是否为空 public Boolean isEmpty(){ return size==0; } public static void main(String[] args) { MyQueueByArray queue=new MyQueueByArray(); queue.offer("a"); queue.offer("b"); queue.offer("c"); System.out.println(queue.peek()); System.out.println(queue.poll()); System.out.println(queue.poll()); System.out.println(queue.poll()); } }
注释还是很详细的,看不懂可以评论哦