(一)栈
- 栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
- 栈一般使用数组实现。
- 压栈:栈的插入操作,在栈顶进行。
- 出栈:栈的删除操作,也在栈顶进行。
- 图示:
- 自己实现栈中的一些方法:
方法 | 作用 |
---|---|
isEmpty() | 判断栈是否为空 |
push(元素) | 压栈 |
peek() | 返回栈顶元素但不删除 |
pop() | 返回栈顶元素且删除 |
size() |
方法的具体实现:
package www.fanfan.com;
//栈:先进后出
//1. 使用数组实现,需要定义一个数组
//2. 每次插入删除等操作都离不开栈顶,定义一个栈顶
// 栈中元素存放下标从0开始,即栈顶开始时下标为0,
// 当把元素插进来以后,栈顶后移,当栈顶大小=数组长度之后栈满
public class MyStack implements StackInterface{
private int[] elem;
private int top;
public MyStack() {
this.elem = new int[5];
this.top = 0;
}
//判断栈是否为空,当栈顶大小0的时候,栈为空
@Override
public boolean empty() {
return this.top == 0;
}
//压栈
//1. 判断栈是否已满,满的话抛出异常
//2. 若栈不满
//2.1 在栈顶位置插入元素
//2.2 栈顶后移
@Override
public void push(int item) {
if(this.top == this.elem.length){
throw new IndexOutOfBoundsException("数组已满");
}
this.elem[this.top] = item;
this.top++;
}
//返回栈顶元素,但不出栈
//1. 判断栈是否为空,若为空,抛出异常
//2. 若栈不为空,直接返回栈顶元素
@Override
public int peek() {
if (empty()){
throw new IndexOutOfBoundsException("栈不能为空");
}
return this.elem[this.top-1];
}
//返回栈顶元素,并且删除
//1. 判断栈是否为空,若为空,抛出异常
//2. 若栈不为空,直接返回栈顶元素
@Override
public int pop() {
if (empty()){
throw new IndexOutOfBoundsException("栈不能为空");
}
int temp = this.elem[top-1];
top--;
return temp;
}
//返回栈中元素个数
@Override
public int size() {
return this.top;
}
//打印栈中元素
public void display(){
for (int i = 0; i < this.top; i++){
System.out.print(this.elem[i]+" ");
}
System.out.println();
}
}
测试类:
package www.fanfan.com;
public class StackTest {
public static void main(String[] args) {
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.push(3);
myStack.display();
System.out.println("返回栈顶元素但不删除:"+myStack.peek());
myStack.display();
System.out.println("返回栈顶元素并不删除:"+myStack.pop());
myStack.display();
}
}
(二)队列
- 队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 。
- 入队列:进行插入操作的一端称为队尾 。
- 出队列:进行删除操作的一端称为队头。
- 队列一般使用链表实现。
- 图示:
- 队列的一些方法使用:
队列有头有尾,而且使用链表实现,即可以定义队列的头节点和尾节点。
而且这样可以使入队和出队的时间复杂度都为O(1).
方法使用如下:
package www.fanfan.com;
//队列:先进先出
//使用链表实现,且队列有头有尾可以定义头节点和尾结点
public class MyQueue implements QueueInterface {
//定义节点类
class Node{
private int data;
private Node next;
public Node(int data) {
this.data = data;
this.next = null;
}
}
//定义头节点和尾节点
//定义队列的长度
private Node head;
private Node tail;
private int usedSize;
public MyQueue() {
this.head = null;
this.tail = null;
this.usedSize = 0;
}
//判断队列是否为空
//头节点为空即为空队列
@Override
public boolean empty() {
return this.head == null;
}
//向队列中添加元素,尾插
//1. 如果队列为空,直接插入,即头节点=尾节点=新插入的节点
//2. 如果队列不为空,则在尾结点插入,不用管头节点
//3.插入完成结束之后,队列长度加一
@Override
public void add(int item) {
Node node = new Node(item);
if (this.head == null){
this.head = node;
this.tail = node;
}else {
this.tail.next = node;
this.tail = node;
}
this.usedSize++;
}
//返回队首元素,但是不删除
//1. 如果队列为空,抛出异常
//2. 如果队列不为空,返回队首元素,头节点后移
@Override
public int peek() {
if (empty()){
throw new IndexOutOfBoundsException("队列为空不能返回队首元素");
}
return this.head.data;
}
//返回队首元素并且删除
//1. 如果队列为空,抛出异常
//2. 如果队列不为空,
//2.1 先保存队首元素的数据
//2.2 头节点后移
//2.3 队列长度减一
//返回保存的队首元素
@Override
public int poll() {
if (empty()){
throw new IndexOutOfBoundsException("队列为空不能返回队首元素");
}
int temp = this.head.data;
this.head = this.head.next;
this.usedSize--;
return temp;
}
@Override
public int size() {
return this.usedSize;
}
public void display(){
Node cur = this.head;
while (cur != null){
System.out.print(cur.data+" ");
cur = cur.next;
}
System.out.println();
}
}
测试类:
package www.fanfan.com;
public class QueueTest {
public static void main(String[] args) {
MyQueue myQueue = new MyQueue();
System.out.println(myQueue.empty());
myQueue.add(1);
myQueue.add(2);
myQueue.add(3);
myQueue.display();
System.out.println(myQueue.peek());
myQueue.display();
System.out.println(myQueue.poll());
myQueue.display();
System.out.println(myQueue.size());
}
}