目录
什么是栈
栈是一种特殊的线性表,它 只允许在固定的一端进行插入和删除元素操作 。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守 先进后出 的原则。模拟实现栈
通过数组和链表都可以实现栈,下面我们通过数组来实现一个栈。
•栈的属性
//实现栈的数组 public int[] elem; //栈里元素的有效个数 public int usedSize; //数组的初始大小 public static final int DEFAULT_SIZE = 10;
•栈的构造方法
//初始化数组大小 public MyStack() { this.elem = new int[DEFAULT_SIZE]; }
•入栈方法
//入栈 public int push(int val) { //判断当前栈是否满了 if (isFull()) { elem = Arrays.copyOf(elem, elem.length * 2); } //将val值入栈并使有效个数加一 elem[usedSize++] = val; return val; } //判断当前栈是否满了 public boolean isFull() { return usedSize == elem.length; }
•判断当前栈是否为空
//判断当前栈是否为空 public boolean empty() { return usedSize == 0; }
•出栈方法
public int pop() { //判断当前栈是否为空 if (empty()) { throw new MyEmptyStackException("pop():栈为空!"); } //返回栈顶元素并使有效个数减一 return elem[--usedSize]; }
自定义异常类:
public class MyEmptyStackException extends RuntimeException { public MyEmptyStackException() { } public MyEmptyStackException(String message) { super(message); } }
•获取栈顶元素
//获取栈顶元素 public int peek() { //判断是否为空 if (empty()) { throw new MyEmptyStackException("peek():栈为空!"); } //返回栈顶元素 return elem[usedSize-1]; }
•获取栈的大小
//获取栈的大小 public int size() { return usedSize; }
Stack
Java集合里的stack就是栈,它的底层是通过数组实现的。
通过上图可知,Stack 继承了 Vector( Vector 和 ArrayList 都是动态的顺序表,不同的是Vector是线程安全的) ,故 Stack 也是线程安全的。
Stack 除了包括由 Vector 定义的所有方法,也定义了自己的一些方法。
Stack的方法
方法 描述 Stack() 构造一个空的栈 Object push(Object element) 将elmement元素入栈,并作为此函数的值返回 Object pop()
将栈顶元素出栈,并作为此函数的值返回 Object peek() 查看栈顶元素,但不从栈中移除它 int size() 获取栈中有效元素个数boolean empty() 检测栈是否为空 int search(Object element) 返回元素在堆栈中的位置,以 1 为基数,先入栈的位置靠后 import java.util.Stack; public class Test { 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.search(1)); //获取2在栈中的位置--->3 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()); } } }
队列
什么是队列
队列是只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表。 进行插入操作的一端称为队尾,进行删除操作的一端称为队头。队列具有 先进先出 的特点。模拟实现队列
队列同样可以通过数组和链表实现,下面我们一起通过双向链表来实现一个队列。
•链表的节点
//定义节点 static class ListNode { //节点的值 int val; //指向前一个节点 ListNode prev; //指向后一个节点 ListNode next; //初始化节点的值 public ListNode(int val) { this.val = val; } }
•列表的属性
//队头 ListNode head; //队尾 ListNode tail; //有效个数 int usedSize;
•入队列
//入队列(尾插) public void offer(int val) { //实例化一个新节点 ListNode node = new ListNode(val); //尾插法 if (this.head == null) { this.head = node; this.tail = node; } else { this.tail.next = node; node.prev = this.tail; this.tail = node; } //有效数字加一 usedSize++; }
•出队列
//出队列(头出) public int poll() { int val = 0; if (head == null) { //队列为空 return null; } else if (this.head == this.tail) { //队列中只有一个元素 val = this.head.val; this.head = null; this.tail = null; } else { //队列中有多个元素 val = this.head.val; this.head = this.head.next; this.head.prev = null; } //有效数字减一 usedSize--; //返回被弹出队列的值 return val; }
•查看队头元素
//查看队头元素 public int peek() { if (head == null) { return null; } return this.head.val; }
•获取队列大小
//获取队列大小 public int size() { return usedSize; }
•判断队列是否为空
//判断队列是否为空 public boolean isEmpty() { return usedSize == 0; }
Queue
在Java集合中Queue是个接口,底层是通过双向链表实现的。
由图中可以看成,Queue 和 Deque 都是个接口,故在实例化 Queue 时必须实例化 LinkedList的对象,因为 LinkedList 实现了Queue 接口。
Queue的方法
方法 描述 boolean add(E e)
将指定的元素插入到此队列中,如果当前没有可用空间,则抛出异常 E element()
检索但不删除此队列的头,如果此队列为空,则抛出异常 E remove()
检索并删除此队列的头,如果此队列为空,则抛出异常 boolean offer(E e)
将指定的元素插入到此队列中,如果当前没有可用空间,则返回flase E peek()
检索但不删除此队列的头,如果此队列为空,则返回 null
。E poll()
检索并删除此队列的头,如果此队列为空,则返回 null
。 int size() 获取队列中有效元素个数 boolean isEmpty() 检测队列是否为空public class Test { public static void main(String[] args) { Queue<Integer> q = new LinkedList<>(); q.offer(1); q.offer(2); q.offer(3); q.offer(4); q.offer(5); // 从队尾入队列 System.out.println(q.size()); System.out.println(q.peek()); // 获取队头元素 q.poll(); System.out.println(q.poll()); // 从队头出队列,并将删除的元素返回 if(q.isEmpty()){ System.out.println("队列空"); }else{ System.out.println(q.size()); } } }