1.栈(Stack)
1.1 概念
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据在栈顶。
1.2 实现
-
利用顺序表实现。即使用 尾插+尾删。
-
利用链表实现,则头尾皆可
//用顺序表实现
public class MyStack {
private int[] data=new int[100];
private int size=0;
//1.入栈
public void push(int val){
if (size>=data.length){
return;
}
data[size]=val;
size++;
}
//2.出栈,返回被出栈元素
public Integer pop(){
if (size==0){
return null;
}
int ret=data[size-1];
size--;
return ret;
}
//3.取出栈顶元素
public Integer peek(){
if(size==0){
return null;
}
return data[size-1];
}
}
//使用链表实现
class Node{
int val;
Node next;
public Node(int val){
this.val=val;
}
}
public class MyStack2 {
private Node head=null;//使用不带傀儡节点的链表
//1.入栈
public void push(int val){
Node newNode= new Node(val);
//相当于给链表进行头插,需要判断链表是否为空
if(head==null){
head=newNode;
return;
}
newNode.next=head;
head=newNode;
}
//2.出栈
public Integer pop(){
//相当于进行头删
if(head==null){
return null;
}
if(head.next==null){
int ret=head.val;
head=null;
return ret;
}
int ret=head.val;
head=head.next;
return ret;
}
//3.取出栈顶元素
public Integer pek(){
if(head==null){
return null;
}
return head.val;
}
}
2.队列(Queue)
2.1概念
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)
入队列:进行插入操作的一端称为队尾(Tail/Rear)
出队列:进行删除操作的一端称为队头(Head/Front)
2.2实现
队列也可以用数组和链表实现,使用链表的结构实现更优一些,如果使用数组的结构,出队列在数组头上的数据,效率会比较低。
//使用链表实现队列
public class MyQueue {
static class Node{
int val;
Node next;
public Node(int val){
this.val=val;
}
}
//记录头结点和尾节点
private Node head=null;
private Node tail=null;
//1.入队列。返回插入成功/失败
public boolean offer(int val){
Node newNode=new Node(val);
if(head==null){
head=newNode;
tail=newNode;
return true;
}
tail.next=newNode;
tail=tail.next;
return true;
}
//2.出队列
public Integer poll(){
if(head==null){
return null;
}
int ret=head.val;
if(head.next==null){
head=null;
return ret;
}
head=head.next;
return ret;
}
//3.取队首元素
public Integer peek(){
if(head==null){
return null;
}
return head.val;
}
public static void main(String[] args) {
MyQueue myQueue=new MyQueue();
myQueue.offer(1);
myQueue.offer(2);
myQueue.offer(3);
myQueue.offer(4);
Integer ret=null;
ret=myQueue.poll();
System.out.println("ret="+ret);
ret=myQueue.poll();
System.out.println("ret="+ret);
ret=myQueue.poll();
System.out.println("ret="+ret);
ret=myQueue.poll();
System.out.println("ret="+ret);
}
}
//使用数组来实现
public class MyQueen2 {
private int[] data=new int[100];
private int head=0;
private int tail=0;
private int size=0;
//1.入队列
public boolean offer(int val){
if(size==data.length){
return false;
}
data[tail]=val;
tail++;
if (tail==data.length){
tail=0;
}
size++;
return true;
}
//2.出队列
public Integer poll(){
if(size==0){
return null;
}
int ret=data[head];
head++;
if(head==data.length){
head=0;
}
size--;
return ret;
}
//3.取队首元素
public Integer peek(){
if(size==0){
return null;
}
return data[head];
}
}
2.3循环队列
实际中我们有时还会使用一种队列叫循环队列。如操作系统课程讲解生产者消费者模型时可以就会使用循环队列。环形队列通常使用数组实现。
数组下标循环的小技巧
- 下标最后再往后(offset 小于 array.length): index = (index + offset) % array.length
- 下标最前再往前(offset 小于 array.length): index = (index + array.length - offset) % array.length
如何区分空满:
1.通过添加一个size属性
2.保留一个位置