目录
栈
栈(Stack):是一种基于后进先出(LIFO)原则的数据结构,只允许在一端插入和删除元素。在栈中,插入元素的一端被称为栈顶,删除元素的一端被称为栈底。栈用于许多算法和应用程序中,如寻路算法、内存管理和表达式求值等。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据在栈顶。
+---------+
| X |
+---------+
| |
| Y |
+---------+
| Z |
+---------+
在空栈上压入元素X,成为新的栈顶元素。
+---------+
| |
+---------+
| Y |
+---------+
| Z |
+---------+
从上图栈中删除栈顶元素X,并返回元素X。
public static void main(String[] args) {
Stack<Integer> s = new Stack();
s.push(1);
s.push(2);
s.push(3);
s.push(4);
System.out.println(s.size()); // 获取栈中有效元素个数4
System.out.println(s.peek()); // 获取栈顶元素4
s.pop(); // 4出栈,栈中剩余1 2 3,栈顶元素为3
System.out.println(s.pop()); // 3出栈,栈中剩余1 2 栈顶元素为3
if(s.empty()){
System.out.println("栈空");
}else{
System.out.println(s.size());
}
}
实现一个Mystack
栈的功能并不多,我们首先创建一个栈:
public class MyStack {
public int[] elem;
public int usedSize;
public static final int DEFAULT_SIZE = 10;
public MyStack() {
this.elem = new int[DEFAULT_SIZE];
}
}//创建一个数组就是创建一个栈,大小初始化为10,usedSize为使用的栈空间,同时是当前栈顶的元素的下标
1.push
public int push(int val) {
if(isFull()) { //判断栈是否为满,若满则扩容两倍空间
elem = Arrays.copyOf(elem,2*elem.length);
}
this.elem[usedSize] = val; 下标为usedSize的元素为push的值
usedSize++;
return val;
}
public boolean isFull() {
return usedSize == elem.length; 通过查看usedSize是否等于数组的长度来判断
}
2.pop
public int pop() {
if(empty()) {
throw new MyEmptyStackException("栈为空!");
}
/*int ret = elem[usedSize-1];
usedSize--;
return ret;*/
return elem[--usedSize];
}
public class MyEmptyStackException extends RuntimeException{
public MyEmptyStackException() {
}
public MyEmptyStackException(String message) {
super(message);
}
}
3.empty
public boolean empty() {
return usedSize == 0;
}
4.peek
public int peek() {
if(empty()) {
throw new MyEmptyStackException("栈为空!");
}
return elem[usedSize-1];
}//peek只获取栈顶的元素,并不会删除元素
栈和链表的结合
逆序打印链表:
// 递归实现
void printList(Node head){
if(null != head){
printList(head.next);
System.out.print(head.val + " ");
}
}
//循环实现
void printList(Node head){
if(null == head){
return;
}
Stack<Node> s = new Stack<>();
//将链表中的结点保存在栈中
Node cur = head;
while(null != cur){
s.push(cur);
cur = cur.next;
}
概念的区分:
栈、虚拟机栈、栈帧有什么区别?
栈:是一种先进后出的数据结构。
虚拟机栈:是JVM的一块内存空间。
栈帧:是在调用函数的过程中,在java虚拟机栈上开辟的一块内存。
队列
队列(Queue)是计算机科学中一种常见的数据结构,它是一种特殊的线性表,只允许在表的前端进行删除操作,在表的后端进行插入操作。也就是说,队列遵循“先进先出”(First In First Out,FIFO)的原则。
java当中的队列基本上就是双向链表来实现的,我们尝试通过单链表来实现一个队列,并且时间复杂度为O(1)。
1.从头入队
入队时间复杂度: O(1)
出队的时间复杂度: O(n)
2.从尾入队入队时间复杂度: O(n)
出队的时间复杂度: O(1)
那该如何实现呢?通过给队尾加上一个tail,这样就可以让出入队时间复杂度都为O(1).
static class ListNode{
public int val;
public ListNode next;
public ListNode(int val) {
this.val = val;
}
}
public ListNode head;
public ListNode tail;
public int Usedsize = 0;
offer(入队列)
//我们从尾入元素,从头出元素。类似于单链表里面的尾插法,从尾插入一个元素,Usedsize++。但我们仍需要注意链表如果为空需要分情况讨论。
public void offer(int val){
ListNode node = new ListNode(val);
if(head == null){
head = node;
tail = node;
}else{
tail.next = node;
tail = tail.next;
}
Usedsize++;
}
poll(出队列)
//只需要把head节点往后移,再返回之前的头结点的val值就能完成,仍需要注意head为空的情况
public int poll(){
if(head == null){
return -1;
}
int ret = head.val;
head = head.next;
if(head == null){ 此时head已经是原head之后的节点了,如果head为空那么tail也需要置空
tail = null;
}
Usedsize--;
return ret;
}
peek(获取队头元素)
public int peek(){
if(head == null){
return -1;
}
return head.val;
}
empty(判断是否为空)
public boolean empty(){
return Usedsize == 0;
}
栈和队列就暂时写到这里了,但仍有很多细节和操作未提及,如果大家有什么问题,欢迎交流指正!