目录
栈和队列
栈的概念和实现
栈的概念
栈是一种特殊的线性表,它只允许在其固定的一端进行插入和删除操作,进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的元素遵循先入后出的规则。
栈的插入也叫入栈、压栈、进栈。是将入栈元素存放在栈顶,栈顶元素变更为新存放的元素。
栈的删除也叫出栈。是将栈顶元素删除。栈顶元素变为删除后的栈顶元素的下一个元素。
栈的基本操作
栈的操作一般常用的为初始化,入栈,出栈,获取栈顶元素,判断栈是否为空,判断栈是否已满。这些操作代码将会在栈的实现中出现。
用链表和顺序表实现栈
栈的实现主要可以靠顺序表或者链表来实现。但是由于是在队尾操作,所以根据顺序表和链表的特性,一般顺序表实现比较简单。
顺序表实现栈
import java.util.Arrays;
public class MyStack {
//顺序表的底层是数组,因此使用数组来存储栈元素;
public int [] elem;
public int top;//用来获取栈的长度,防止数组越界异常。
public MyStack(){//构造栈
elem = new int [10];
top = 0;
}
public boolean isFull(){//判满
if(top == elem.length){
return true;
}else{
return false;
}
}
public void push(int val){//入栈操作
if(isFull()){//扩容
Arrays.copyOf(elem , elem.length * 2);
}
elem[top] = val;
top++;
}
public int pop() {//出栈
if(empty()){
return -1;
}
int ret = elem[top - 1];
top--;
return ret;
}
public boolean empty(){//判空
if(top == 0){
return true;
}else{
return false;
}
}
public int peek(){//获取栈顶元素
if(empty()){
return -1;
}
return this.elem[this.top - 1];
}
}
链表实现栈
class StackNode{
public int value;//存放的数据
public StackNode next;//指向下一个节点
public StackNode(int val){//构造函数
value = val;
}
}
public class MyStack {
public StackNode front;
public StackNode rear;
public int usedSize = 0;
public void push(int num){//入栈
StackNode stackNode = new StackNode(num);
if(front == null){
front = stackNode;
rear = stackNode;
}else{
rear.next = stackNode;
rear = stackNode;
}
usedSize++;
}
public int pop(){//出栈
if(empty()){
return -1;
}
int ret = rear.value;
if(usedSize == 1){
front = null;
rear = null;
}else{
StackNode cur = front;
int num = 1;
while(num != (usedSize - 1)) {
cur = cur.next;
num++;
}
rear = cur;
rear.next = null;
usedSize--;
}
return ret;
}
public boolean empty(){//判空
return front == null;
//return usedSize == 0;
}
public int peek(){//获取栈顶元素
if(empty()){
return -1;
}
return rear.value;
}
实现最小栈
通过栈来获取数据中的最小值。
import java.util.Stack;
public class MinStack {
public Stack<Integer> stack;
public Stack<Integer> minStack;
public MinStack(){
stack = new Stack<>();
minStack = new Stack<>();
}
//入栈
public void push(int val){
stack.push(val);
if(minStack.empty()){
minStack.push(val);
}else {
int num = minStack.peek();
if(val <= num){
minStack.push(val);
}
}
}
//出栈
public void pop(){
if(minStack.isEmpty()){
return;
}
int num = stack.pop();
int min = minStack.peek();
if(num == min){
minStack.pop();
}
}
//普通栈顶元素
public int top(){
if(stack.empty()){
return -1;
}
return stack.peek();
}
//最小栈顶元素
public int getMin(){
if(minStack.empty()){
return -1;
}
return minStack.peek();
}
}
队列的概念与实现
队列的概念
队列是只允许在一端插入数据而在另一端进行删除数据的一种特殊线性表,队列遵循着先入先出的规则。
其中入队列是进行数据插入的操作,这一端称为队尾。
出队列是进行数据删除的操作,这一端称为队头。
队列的基本操作
队列的基本操作一般有入队列,出队列,判断队列是否为空,获取队首元素。这些代码在队列的实现中展示。
队列的实现
队列的实现也可以用顺序表和链表来进行实现,但是由于是两端操作,所以根据顺序表和链表的特性,一般链表实现比较简单。
链表实现队列
class QueueNode{
public int value;//节点存放的数据
public QueueNode next;//指向下一个节点
public QueueNode(int val){//构造函数
this.value = val;
}
}
public class MyQueue {
public QueueNode front;//头
public QueueNode rear; //尾
public int usedSide;
//入队列
public void offer(int value){
QueueNode queueNode = new QueueNode(value);
if(this.front == null){
this.front = queueNode;
this.rear = queueNode;
}else {
this.rear.next = queueNode;
this.rear = queueNode;
}
this.useSide++;
}
//出队
public int poll(){
if(this.isEmpty()){
return -1;
}
int ret = this.front.value;
this.front = this.front.next;
this.useSide--;
return ret;
}
public boolean isEmpty(){
return this.front == null;
}
//获取队首元素
public int peek(){
if(this.isEmpty()){
return -1;
}
return this.front.value;
}
public int size(){
return this.useSide;
}
}
顺序表实现队列
import java.util.Arrays;
public class MyQueue {
public int [] arr;
public int len;
public int top;
public MyQueue(){
arr = new int[10];
len = 0;
top = 0;
}
//判满
public boolean isFull(){
if(len == arr.length){
return true;
}else{
return false;
}
}
//入队列
public void offer(int value){
if(isFull()){//满了扩容
Arrays.copyOf(arr , arr.length * 2);
}
arr[len++] = value;
}
//判空
public boolean isEmpty(){
if(top == len){
return true;
}else{
return false;
}
}
//出队列
public int poll(){
if(isEmpty()){
return -1;
}
int ret = arr[top];
arr[top++] = 0;
return ret;
}
//获取队首元素
public int peek(){
if(isEmpty()){
return -1;
}
return arr[top];
}
//队列长度
public int size(){
return len - top;
}
}
循环队列及实现
循环队列就是将队列变成一个环状,在上述的数组实现队列时,队列大量的进行删除操作会造成队首元素后移,从而造成数组0下标到队列队首下标之间的浪费,而循环链表就可以解决这种资源浪费。但循环队列的缺点是它的队列长度给定了,无法在进行扩容,因此在使用时需要提前判断数据的大小来给定队列的大小。
public class MyCircularQueue {
public int [] elem;
public int front;
public int rear;
//虽然给定的队列长度是k,但是由于有进行队尾元素的操作和判断,
//所以真正的队列长度为k+1.
public MyCircularQueue(int k){
elem = new int[k + 1];
}
//入队
public boolean enQueue(int value){
if(isFull()){
return false;
}
elem[rear] = value;
rear = (rear + 1) % elem.length;
return true;
}
//出队
public boolean deQueue(){
if(isEmpty()){
return false;
}
front = (rear + 1) % elem.length;
return true;
}
public int Front(){//获得队首元素
if(isEmpty()){
return -1;
}
return elem[front];
}
public int Rear(){//获得队尾元素
if(isEmpty()) {
return -1;
}
if(rear == 0){
return elem[elem.length - 1];
}
return elem[rear - 1];
}
public boolean isEmpty(){//判断队列是否为空
return front == rear;
}
public boolean isFull(){//判断队列是否存满
//判断rear的下一个是不是front
if((rear + 1) % elem.length == front){
return true;
}
return false;
}
//打印
public void display(){
for(int i = 0 ; i < elem.length - 1 ; i++){
System.out.print(elem[i]);
}
System.out.println();
}
}
双端队列
双端队列是指两端都能进行入队和出队的操作的队列,那就说明元素可以从队首入队和出队,也能从队尾进行入队和出队。它的代码和普通队列类似,只需要增加堆首入队和队尾出队方法就可实现。
栈和队列的相互转换
用栈实现队列
class MyQueue {
public Stack<Integer> stack1;
public Stack<Integer> stack2;
public MyQueue() {
stack1 = new Stack<>();
stack2 = new Stack<>();
}
//入队列
public void push(int x) {
stack1.push(x);
}
//出队列
public int pop() {
if(stack2.isEmpty()){
while(!stack1.isEmpty()){
stack2.push(stack1.pop());
}
}
return stack2.pop();
}
//查看队首元素
public int peek() {
int num = 0;
if(stack2.isEmpty()){
while(!stack1.isEmpty()){
num = stack1.pop();
stack2.push(num);
}
}
return stack2.peek();
}
//判空
public boolean empty() {
return stack1.isEmpty() && stack2.isEmpty();
}
}
用队列实现栈
class MyStack {
public Queue<Integer> queue1;
public Queue<Integer> queue2;
public MyStack() {
queue1 = new LinkedList<>();
queue2 = new LinkedList<>();
}
//入栈
public void push(int x) {
queue2.offer(x);
while(!queue1.isEmpty()){
queue2.offer(queue1.poll());
}
Queue<Integer> tmp = queue1;
queue1 = queue2;
queue2 = tmp;//经过两个队列的交换,queue1最后的顺序变为栈操作的顺序
}
//出栈
public int pop() {
return queue1.poll();
}
//查看栈顶元素
public int top() {
return queue1.peek();
}
//判空
public boolean empty() {
return queue1.isEmpty();
}
}