1.栈
1.1概念
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据在栈顶。
基于数组来实现栈,数组的尾插尾删比较高效,头插头删比较低效。就使用尾插作为入栈,尾删作为出栈,取栈顶元素,就是获取到数组的末尾的元素。
基于链表来实现栈,链表的头插头删比较方便。尾插尾删虽然可以通过额外记录tail引用的方式来实现,但是代码更复杂一些。
1.2实现
1.2.1用顺序表实现栈
利用顺序表实现,即使用尾插 + 尾删的方式实现
public class myStack {
private int[] data = new int[100];
private int size = 0;
//入栈
public void push(int val){
if(size >= data.length){
//在这里也可以进行扩容
return;
}
data[size] = val;
size++;
}
//出栈 返回值就是那个被出栈了的元素
public Integer pop(){
if(size == 0){
return null;
}
//栈顶元素就是最后一个元素
int ret = data[size - 1];
size--;
return ret;
}
//取栈顶元素
public Integer peek(){
if(size == 0){
return null;
}
return data[size - 1];
}
}
1.2.2用链表实现栈
利用链表实现,则头尾皆可
class Node{
int val;
Node next;
public Node(int val){
this.val = val;
}
}
public class myStack2 {
//使用不带傀儡节点来表示
//private Node getHead = new Node(-1);
private Node head = null;
//入栈
private void push(int val){
Node newNode = new Node(val);
//把新节点进行头插
//当前是不带傀儡节点的,所以需要判断当前链表是否为空
if(head == null){
head = newNode;
return;
}
newNode.next = head;
head = newNode;
}
//出栈
//此处是pop返回值表示被删除的元素的值,设置成void也是可以的
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;
}
//获取栈顶元素
public Integer peak(){
if(head == null){
return null;
}
return head.val;
}
}
2队列
2.1概念
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)的特点
入队列:进行插入操作的一端称为队尾(Tail/Rear)
出队列:进行删除操作的一端称为队头(Head/Front)
2.2实现
2.2.1用链表实现队列
class Node{
int val;
Node next;
public Node(int val){
this.val = val;
}
}
public class myQueue {
//创建一个链表的头节点
//为了方便的进行尾插,记录尾节点
private Node head = null;
private Node tail = null;
//入队列
//返回值表示插入成功/失败
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;
}
//出队列,头删
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;
}
//取队首元素
public Integer peak(){
if(head == null){
return null;
}
return head.val;
}
}
2.3环形队列
可以看出,出队列和入队列都是环形的,它两的时间复杂度都是O(1)
2.3.1使用数组实现环形队列
代码如下:
public class myQueue2 {
private int[] data = new int[100];
//队列有效区间[head ,tail)
private int head = 0;
private int tail = 0;
private int size = 0;//元素个数
//核心操作
//1.入队列
public boolean offer(int val){
if(size == data.length){
return false;
}
//把新元素放到tail对应的下标上
data[tail] = val;
tail++;
//一旦到打了数组末尾,就需要让数组从头开始
if(data.length == tail){//也可以写成 tail = tail %data.length
tail = 0;
}
size++;
return true;
}
//2.出队列
public Integer pool(){
if(size == 0){
return null;
}
int ret = data[head];
head++;
if(head ==data.length){
head = 0;
}
size--;
return ret;
}
//3.取队首元素
public Integer peak(){
if(size == 0){
return null;
}
return data[head];
}
}