栈,是一种特殊的链表,是一种只能在表尾进行操作的特殊链表,是一种后进先出的结构。
一、栈的结构
栈本质是一种链表,因此栈存储结构与链表一致,形象图如下:
整个栈像我们日常使用的行礼箱,它是一层一层的放置东西,每件物品相当于一个栈元素,我们如果想放东西,只能从下面往上面放,最后放的东西永远在最上面,如果拿东西,也是从第上面开始拿
1.给栈添加元素
- 就像往箱子里面放东西,后放的东西总是在最上面
2.从栈里面删除元素
- 就像拿东西,东西总是从上面开始拿
二、通过数组实现栈
通过数组来实现栈是比较简单的,因为栈只操作表尾,即数组的最后一个元素,其主要操作主要是入栈和出栈。
1.入栈
在栈尾添加节点
2.出栈
弹出栈尾元素节点
3.通过数组来实现栈这种数据结构
package com.shixinke.demo.dataStruct;
public class MyArrayStack<E> {
//栈的大小
private int size;
//栈存储的元素节点
private E[] data;
private static final int DEFAULT_CAPACITY = 10;
public MyArrayStack() {
clearStack(DEFAULT_CAPACITY);
}
public MyArrayStack(int capacity) {
clearStack(capacity);
}
public void clear() {
clearStack(DEFAULT_CAPACITY);
}
/**
* 清除栈
* @param capacity
*/
private void clearStack(int capacity) {
this.size = 0;
ensureCapacity(capacity);
}
/**
* 获取栈的大小
* @return
*/
public int size() {
return this.size;
}
/**
* 是否为空栈
* @return
*/
public boolean isEmpty() {
return this.size == 0;
}
/**
* 栈是否包含某个元素
* @param value
* @return
*/
public boolean contains(E value) {
return indexOf(value) == -1 ? false : true;
}
/**
* 获取某个元素在栈中的位置(第一次)
* @param value
* @return
*/
public int indexOf(E value) {
for (int i = 0; i< this.size; i++) {
if (value.equals(this.data[i])) {
return i;
}
}
return -1;
}
/**
* 获取某个元素在栈中最后一次出现的位置
* @param value
* @return
*/
public int lastIndexOf(E value) {
for (int i = this.size - 1; i >= 0; i--) {
if (value.equals(this.data[i])) {
return i;
}
}
return -1;
}
/**
* 向栈添加元素
* @param value
* @return
*/
public boolean push(E value) {
if (this.data.length == this.size) {
ensureCapacity(this.size * 2 + 1);
}
this.data[size] = value;
this.size ++;
return true;
}
/**
* 从栈中取出元素
* @return
*/
public E pop() {
if (this.size == 0) {
return null;
}
E value = this.data[this.size - 1];
this.size --;
return value;
}
/**
* 给栈中某个位置设置值
* @param index
* @param value
*/
public void set(int index, E value) {
if (index > this.size) {
throw new IndexOutOfBoundsException();
}
this.data[index] = value;
}
/**
* 获取某个位置的元素
* @param index
* @return
*/
public E get(int index) {
if (index > this.size) {
throw new IndexOutOfBoundsException();
}
return this.data[index];
}
/**
* 栈扩容
* @param capacity
*/
private void ensureCapacity(int capacity) {
//新容量比原表大小还小,直接返回,不需要扩容
if (capacity < this.size) {
return;
}
E[] oldData = data;
data = (E[]) new Object[capacity];
for (int i = 0; i < this.size; i++) {
data[i] = oldData[i];
}
}
/**
* 打印栈的元素
*/
public void print() {
System.out.println();
System.out.print("[");
for (int i = 0; i< this.size; i++) {
System.out.print(this.data[i]);
if (i != this.size - 1) {
System.out.print(",");
}
}
System.out.println("]");
System.out.println();
}
/**
* 演示使用(代码可移动到测试代码中)
*/
public static void main(String[] args) {
MyArrayStack<String> books = new MyArrayStack<String>(5);
books.push("JAVA编程");
books.push("网络安全");
books.push("计算机网络");
books.push("计算机文化基础");
books.print(); //[JAVA编程,网络安全,计算机网络,计算机文化基础]
String lastBook = books.pop();
System.out.println(lastBook); //计算机文化基础
books.print(); //[JAVA编程,网络安全,计算机网络]
System.out.println(books.size()); //3
System.out.println(books.contains("计算机网络")); //true
System.out.println(books.indexOf("计算机网络")); //2
}
}
三、通过链表实现栈
1.入栈
- 生成一个新的节点(它的prev指针指向表尾节点,next指针指向null)
- 将原表尾节点的next指针指向新表尾节点
- 将新表尾指向新的表尾节点
- 表节点个数加1
2.出栈
- 将原表尾节点的前一个节点的next指向指向null
- 将表尾指向原节点的前一个节点
- 清除了原表尾的资源,内容和prev指针都为null
- 表节点个数减1
3.通过链表实现栈
package com.shixinke.demo.dataStruct;
public class MyLinkedStack<E> {
private int size;
private Node<E> first;
private Node<E> last;
public MyLinkedStack() {
clearStack();
}
public void clear() {
clearStack();
}
/**
* 清除栈的资源
*/
public void clearStack() {
this.size = 0;
this.first = null;
this.last = null;
}
/**
* 入栈
* @param value
* @return
*/
public boolean push(E value) {
//1.生成新的表尾节点(prev指针指向原表尾,next指针指向null)
Node<E> node = new Node<E>(value, this.last, null);
//2.如果原表尾为null,即原表为空表,则将表头指向新添加的表尾节点
if (this.last == null) {
this.first = node;
} else {
//3.如果表尾节点存在,则将原表尾节点指向新插入的表尾节点
this.last.next = node;
}
//4.将新表尾指向新的插入的表尾节点
this.last = node;
//5.增加表的节点个数
this.size ++;
return true;
}
/**
* 出栈
* @return
*/
public E pop() {
//1.如果原表是空表,直接返回null
if (this.last == null) {
return null;
}
//2.获取原表尾节点
Node<E> oldNode = this.last;
//3.将表尾节点指向表尾节点的前一个节点
this.last = this.last.prev;
//4.获取原表尾节点的数据
E value = oldNode.data;
//5.删除原表尾节点上的数据和指针
oldNode.prev = null;
oldNode.next = null;
oldNode.data = null;
//6.减少表的元素个数
size --;
return value;
}
public int size() {
return this.size;
}
public boolean isEmpty() {
return this.size == 0;
}
public boolean contains(E value) {
return indexOf(value) >= 0 ? true :false;
}
public int indexOf(E value) {
if (value == null) {
Node<E> node = first;
for (int i = 0; i< this.size; i++) {
if (node.data == null) {
return i;
}
node = node.next;
}
} else {
Node<E> node = first;
for (int i = 0; i< this.size; i++) {
if (value.equals(node.data)) {
return i;
}
node = node.next;
}
}
return -1;
}
public int lastIndexOf(E value) {
if (value == null) {
Node<E> node = first;
for (int i = this.size - 1; i >= 0; i--) {
if (node.data == null) {
return i;
}
node = node.next;
}
} else {
Node<E> node = first;
for (int i = this.size - 1; i >= 0; i--) {
if (value.equals(node.data)) {
return i;
}
node = node.next;
}
}
return -1;
}
private class Node<E> {
private E data;
private Node<E> prev;
private Node<E> next;
public Node(E value, Node<E> prev, Node<E> next) {
this.data = value;
this.prev = prev;
this.next = next;
}
}
public void print() {
System.out.println();
System.out.print("[");
Node<E> p = first;
for (int i = 0; i < size; i++) {
System.out.print(p.data);
p = p.next;
if (i != size -1) {
System.out.print(",");
}
}
System.out.print("]");
System.out.println();
}
public static void main(String[] args) {
MyLinkedStack<String> books = new MyLinkedStack<String>();
books.push("JAVA编程");
books.push("网络安全");
books.push("计算机网络");
books.push("计算机文化基础");
books.print(); //[JAVA编程,网络安全,计算机网络,计算机文化基础]
String borrowBook = books.pop();
System.out.println(borrowBook); //计算机文化基础
books.print(); //[JAVA编程,网络安全,计算机网络]
System.out.println(books.indexOf("网络安全")); //1
System.out.println(books.contains("JAVA编程")); //true
books.clear();
System.out.println(books.isEmpty()); //true
books.print(); //[]
}
}