目录
- 数组和链表都是线性表。
- 栈和队列作用:限制线性表的插入和删除。
栈
- 特点:先进后出,可以倒叙输出。
- 插入的一端叫栈顶,对应的的另一端不变化叫栈底。
- 只能从栈顶插入,从栈顶删除。
- 只能查看栈顶的元素。
- 插入和删除都能达到的时间复杂度是O(1)。
举例
插入
如果用链表插入使用头插法、尾插法。
底层用数组造一个栈,用数组需要提前开辟好空间。
- 定义一个游标栈顶,指向最底层;
- 栈顶+1,指向要存储数据的位置,把数据放入;
- 栈顶+1,指向要存储数据的位置,把数据放入;
- ......,把所有的数据都放入。
总结:
- 插入:栈顶++,插入数据
- 判断栈满:栈顶arr.length-1是否相等,也可以进行扩容
删除
总结:
- 删除:取出数据,栈顶--
- 判断栈空:栈顶==-1
java代码:
java
package com.xxx;
public class Stack {
int[] arr = new int[5];
int top = -1;//初始化栈为空
//入栈
public void push(int num) {
if (isFull()) {
System.out.println("栈满考虑扩容");
return;
}
top++;
arr[top] = num;
}
//栈满 栈满true 否则false
public boolean isFull() {
return top==arr.length-1;
}
//出栈
public int pop() {
if (isEmpty()) {
throw new RuntimeException("栈空没有数据");//运行时异常
}
int num = arr[top];
top--;
return num;
}
//栈空 栈空true 否则false
public boolean isEmpty() {
return top==-1;
}
public static void main(String[] args) {
Stack stack = new Stack();
stack.push(1);
stack.push(6);
stack.push(8);
stack.push(4);
stack.push(2);
stack.push(9);
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.pop());
}
}
输出结果
java
栈满考虑扩容//栈数组长度位5,但插入了6个数据,最后一个数据没有插入
2
4
8
5
1//栈先进后出取出的数据
Exception in thread "main" java.lang.RuntimeException: 栈空没有数据
at com.zcm.栈.Stack.pop(Stack.java:24)
at com.zcm.栈.Stack.main(Stack.java:58)
//栈插入了5个数据,但取出语句有6个,将5个数据都取出后,最有一个取出语句会报栈空
队列
- 特点:先进先出。
- 从队尾插入,从队头删除。
- 只能查看队头的元素。
队列也是造出来的,用数组、链表都可以。
举例
插入
底层还是用数组来造。
- 定义两个游标:队头front和队尾rear,当前没有任何数据,默认初始值指向-1;
- 插入数据,队尾rear++,指向要插入的位置,插入数据1;
- 队尾rear++,指向要插入的位置,插入数据2;
- ......,把所有的数据都放入。
总结:
- 插入:队尾++,插入数据
- 队满:rear==arr.length-1
删除
- 取出数据,队头front++,指向要取出数据的位置,取出数据1;
- 队头front++,指向要取出数据的位置,取出数据2;
- ......,把所有数据取出及完成。
总结:
- 取出:对头++,取出数据
- 队空:rear==front
java代码:
java
package com.xxx;
public class Queue {
int[] arr = new int[5];
int front = -1;
int rear = -1;
//入队
public void add(int num) {
if (isFull()) {
System.out.println("队满考虑扩容");
return;
}
rear++;
arr[rear] = num;
}
//队满
public boolean isFull() {
return rear==arr.length-1;
}
//出队
public int remove() {
if(isEmpty()) {
throw new RuntimeException("队空异常");
}
front++;
return arr[front];
}
//队空
public boolean isEmpty() {
return rear==front;
}
public static void main(String[] args) {
Queue queue = new Queue();
queue.add(1);
queue.add(2);
queue.add(3);
queue.add(4);
queue.add(5);
queue.add(6);
System.out.println(queue.remove());
System.out.println(queue.remove());
System.out.println(queue.remove());
System.out.println(queue.remove());
System.out.println(queue.remove());
System.out.println(queue.remove());
}
}
输出结果
java
队满考虑扩容//队列数组长度位5,但插入了6个数据,最后一个数据没有插入
1
2
3
4
5//队列先进先出取出的数据
Exception in thread "main" java.lang.RuntimeException: 队空异常
at com.zcm.队列.Queue.remove(Queue.java:32)
at com.zcm.队列.Queue.main(Queue.java:58)
//队列插入了5个数据,但取出语句有6个,将5个数据都取出后,最有一个取出语句会报队列空
循环队列
插入
在上面中取出了所有的数据,那么还想在插入数据如何操作呢?
(队尾++)%arr.length,取余可以插入数据。
- 在上图插入结束中可以看出队尾rear指向下标位4的位置,(队尾rear++)%arr.length为(4+1)➗5余0,队尾rear指向下标为0的位置,继续插入数据;
- (队尾rear++)%arr.length为(0+1)➗5余1,队尾rear指向下标为1的位置,继续插入数据;
- ......,直到空间插满数据。
总结:
- 插入:取余:(队尾++)%arr.length,插入数据
- 队满:front==rear
删除
- 在上图删除结束中可以看出队头front指向下标位4的位置,(队头front++)%arr.length为(4+1)➗5余0,队头front指向下标为0的位置,继续取出数据;
- (队头front++)%arr.length为(0+1)➗5余1,队头front指向下标为1的位置,继续取出数据;
- ......,直到把所有数据取出为止。
总结:
- 取出:取余:(队头++)%arr.length,取出数据
- 队空:front==rear
在循环队列中,可以看出队空和队满都是front==rear,如何解决这个问题?
方法一: 空余一个数据不存
- 空余一个空间不存数据,队满:front==rear+1;
- 队空:front==rear。
方法二: 借助标识,flag=1或flag=0
标识 | |
---|---|
插入:取余:(队尾++)%arr.length,插入数据 | flag=1 |
队满:front==rear | flag=1 |
取出:取余:(队头++)%arr.length,取出数据 | flag=0 |
队空:front==rear | flag=0 |