抽象数据结构的实现 - 栈、队列、背包
抽象数据结构的手动实现
算法第四版
栈 - 长度可变
接口
StackInterface.java
package mystack;
public interface StackInterface<T> {
void push(T item);
T pop();
boolean isEmpty();
int size();
void resize(int newSize);
}
栈类
ResizeStack.java
package mystack;
import java.util.Iterator;
public class ResizeStack<T> implements StackInterface<T>, Iterable<T> {
// 迭代器 start
public Iterator<T> iterator(){
return new ResizeStackIterator();
}
private class ResizeStackIterator implements Iterator<T> {
@Override
public void remove() {
}
@Override
public boolean hasNext() {
return length > 0;
}
@Override
public T next() {
return stack[--length];
}
}
// 迭代器 end
// 实例变量 start
private T[] stack;// 栈
private int length;// 当前栈的长度
// 实例变量 end
// 构造器 start
// 初始时,默认栈的长度是1
// 当内容长度大于栈当前的1/2时,扩充栈的长度至当前的2倍
public ResizeStack(int initLengthOfStack) {
/**
* stack = new T[1];// 这么写java不认,说明泛型不能创建数组
* */
stack = (T[]) new Object[initLengthOfStack];
// 此时 length=0,但是数组已经有元素了
}
// 构造器 stop
// 接口 start
@Override
public void push(T item) {
if (this.length + 1 == this.stack.length){
// 当前的 stack 已经满了的时候,先执行扩容操作
// 然后将新的值放进去
resize(this.stack.length * 2);
}
this.stack[length++] = item;// 如果栈没有满,直接放进去
}
@Override
public T pop() {
if (this.length <= 0) {
throw new ArrayIndexOutOfBoundsException("栈已经是空的");
}
T item = this.stack[--this.length];
this.stack[this.length] = null;
if (this.length <= this.stack.length / 4) {
// 先执行弹出操作
// 然后 resize
resize(this.stack.length / 2);
}
return item;
}
@Override
public boolean isEmpty() {
// 返回栈是否是空
// true 空
// false 非空
return length == 0;
}
@Override
public int size() {
return this.length;
}
@Override
public void resize(int newSize) {
// 将源数组
// 扩充为长度 newSize 的数组
// 这里默认 原长度 比newSize 小
T[] newStack;
newStack = (T[]) new Object[newSize];
for (int i = 0; i < this.length; i++) {
newStack[i] = this.stack[i];
}
this.stack = newStack;
}
// 接口 end
// 状态监测
public int getStackSize() {
return stack.length;
}
}
测试用例
Application.java
package mystack;
public class Application {
public static void main(String[] args) {
String[] tobe = "to be or not to - be - - that - - - is".split(" ");
ResizeStack<String> stringResizeStack = new ResizeStack<>(2);
for (String s : tobe) {
if (!s.equals("-")) { // 当元素 s 不是 “-”, 即 s 是一个单词时
stringResizeStack.push(s);// 将单词送入栈
} else if (!stringResizeStack.isEmpty()) {
System.out.print(stringResizeStack.pop() + " ");
}
System.out.println(" \t栈内元素的个数:" + stringResizeStack.size()
+ "栈的真实长度:" + stringResizeStack.getStackSize());
}
System.out.println("(" + stringResizeStack.size() + " left on stack)");
}
}
输出
栈内元素的个数:1栈的真实长度:2
栈内元素的个数:2栈的真实长度:4
栈内元素的个数:3栈的真实长度:4
栈内元素的个数:4栈的真实长度:8
栈内元素的个数:5栈的真实长度:8
to 栈内元素的个数:4栈的真实长度:8
栈内元素的个数:5栈的真实长度:8
be 栈内元素的个数:4栈的真实长度:8
not 栈内元素的个数:3栈的真实长度:8
栈内元素的个数:4栈的真实长度:8
that 栈内元素的个数:3栈的真实长度:8
or 栈内元素的个数:2栈的真实长度:4
be 栈内元素的个数:1栈的真实长度:2
栈内元素的个数:2栈的真实长度:4
(2 left on stack)
记忆点
-
类实现多个接口
-
声明的时候多个接口用逗号隔开就行了
-
public class ResizeStack<T> implements StackInterface<T>, Iterable<T> {}
-
-
迭代器(以供for遍历等用)
-
声明时,首先实现
Iterable
接口 -
然后在内部建立私有类
-
private class ResizeStackIterator implements Iterator<T> {}
-
最后实现迭代器方法
-
public Iterator<T> iterator(){ return new ResizeStackIterator(); }
-
完整的自然语言用例
-
public class 文件类名<T> implements 自己的接口<T>, Iterable<T> { // 迭代器 start private class 文件类名Iterator implements Iterator<T> { @Override public void remove() { // 实现remove方法 } @Override public boolean hasNext() { // 实现hasNext方法 return length > 0; } @Override public T next() { // 实现next方法 return stack[--length]; } } public Iterator<T> iterator(){ return new 文件类名Iterator(); } }
-
-
泛型数组
- 假设泛型类型参数为
<T>
,类内创建a = new T[cap];
(cap是int)是不被允许的 - 应使用一个IDEA报警告的方法:
a = (T[]) new Object[cap];
创建泛型数组
- 假设泛型类型参数为
-
栈变长度
- push时,若栈满,则扩充栈至原长度2倍
- pop时,若栈的元素个数<栈长度/4,则缩短栈长度至原1/2
-
防止数组类型中值游离
-
对于元素 array[i],当其不需要使用时,或者说数组此时已经希望取0~i-1
-
令 array[i] = null 即可,这里认为 i 之后的数组元素已经是null 或者无元素
-
栈 - 链表实现
栈顶即是链表头
接口
ChainStackInterface.java
package mystack.chainstack;
public interface ChainStackInterface<T> {
boolean isEmpty();
int size();
void push(T t);
T pop();
}
栈类
ChainStack.java
package mystack.chainstack;
import java.util.Iterator;
import java.util.function.Consumer;
public class ChainStack<T> implements ChainStackInterface<T>, Iterable<T>{
// 栈顶等价于链表的头元素(first)
private class ChainStackIterator implements Iterator<T> {
int copyN = N;
Node copyFirst = first;
@Override
public void remove() {
}
@Override
public boolean hasNext() {
return copyN != 0;
}
@Override
public T next() {
copyN--;
Node oldCopyFirst = copyFirst;
copyFirst = copyFirst.next;
return oldCopyFirst.t;
}
}
@Override
public Iterator<T> iterator() {
return new ChainStackIterator();
}
private Node first;
private int N;// 链表长度,栈高度
private class Node {
T t;// 节点保存的内容
Node next;// 链接
@Override
public String toString() {
return "Node{" +
"t=" + t +
", next=" + next +
'}';
}
}
@Override
public boolean isEmpty() {
return N == 0;
}
@Override
public int size() {
return N;
}
@Override
public void push(T t) {
Node oldFirst = this.first;
first = new Node();
first.t = t;
first.next = oldFirst;
N++;
}
@Override
public T pop() {
T tmp = this.first.t;
if (N!=0) {
// 链表有至少一个元素
this.first = this.first.next;
N--;
} else throw new IndexOutOfBoundsException("链表里没有元素了");
return tmp;
}
}
测试用例
Application.java
package mystack.chainstack;
public class Application {
public static void main(String[] args) {
String[] sourString = {"Hello", "World", "Hi", "Test1", "Test2", "Test1", "Test3"};
ChainStack<String> stringChainStack = new ChainStack<>();
for (String s : sourString) {
stringChainStack.push(s);
}
for (String s : stringChainStack) {
System.out.println(s);
}
}
}
输出
Test3
Test1
Test2
Test1
Hi
World
Hello
记忆点
迭代器(遍历列表)
不同于前文中的“破坏性”的遍历,这里为了保持原对象中数据的完整性,计数器和待遍历的节点都应有引用变量或拷贝接收(说不太清楚,总之就是迭代器类只能操作自己类内的数据)
private class ChainStackIterator implements Iterator<T> {
int copyN = N;// 建立迭代器实例变量,不可以破坏原对象的已有数据
Node copyFirst = first;// 建立迭代器实例头节点,不可以破坏原对象的已有数据
@Override
public void remove() {
}
@Override
public boolean hasNext() {
return copyN != 0;// 正确的遍历结束条件
}
@Override
public T next() {
copyN--;
Node oldCopyFirst = copyFirst;// 为了返回当前遍历的节点数据,建立拷贝的节点
copyFirst = copyFirst.next;// 实例节点向后
return oldCopyFirst.t;
}
}
参考书中算法1.4,改进的迭代器为
private class ChainStackIterator implements Iterator<T> {
//int copyN = N;
private Node copyFirst = first;
@Override
public void remove() {
}
@Override
public boolean hasNext() {
return copyFirst != null;// 不再使用计数器
}
@Override
public T next() {// 从创建节点转变为创建泛型
T item = copyFirst.t;
copyFirst = copyFirst.next;
return item;
}
}
@Override
public Iterator<T> iterator() {
return new ChainStackIterator();
}
队列 - 链表实现
接口
ChainQueueInterface.java
package myqueue.chainqueue;
public interface ChainQueueInterface<T> {
boolean isEmpty();
int size();
void push(T t);
T pop();
}
队列类
ChainQueue.java
package myqueue.chainqueue;
import java.util.Iterator;
public class ChainQueue<T> implements ChainQueueInterface<T>, Iterable<T> {
private class ChainQueueIterator implements Iterator<T> {
private Node firstI = first;
//private Node lastI = last;
@Override
public void remove() {
}
@Override
public boolean hasNext() {
return firstI != null;
}
@Override
public T next() {
T itemI = firstI.item;
firstI = firstI.next;
return itemI;
}
}
@Override
public Iterator<T> iterator() {
return new ChainQueueIterator();
}
private class Node {
T item;
Node next;
@Override
public String toString() {
return "Node{" +
"item=" + item +
", next=" + next +
'}';
}
}
private Node first;
private Node last;
private int N;
@Override
public boolean isEmpty() {
return N == 0;
}
@Override
public int size() {
return N;
}
@Override
public void enQueue(T t) {
/**
if (N == 0) {// 初始化链表时,需要将 first last 都指向第一个元素
this.first = new Node();
this.first.item = t;
this.last = this.first;
} else {
this.last.next = new Node();
this.last.next.item = t;
this.last = this.last.next;
}
*/
Node oldLast = last;
this.last = new Node();
this.last.item = t;
this.last.next = null;
if (isEmpty()) {// 空
this.first = this.last;
} else {// 非空
oldLast.next = last;
}
N++;
}
@Override
public T deQueue() {
/**
if (N == 0) {
throw new IndexOutOfBoundsException("队列里面没有元素了");
} else if (N == 1) {
N--;
T item = this.first.item;
this.first = null;
this.last = null;
return item;
} else {
N--;
T item = this.first.item;
this.first = this.first.next;
return item;
}
*/
if (N == 0) {
throw new IndexOutOfBoundsException("队列里面没有元素了");
}
T item = first.item;
this.first = this.first.next;
if (N == 1) {
this.last = this.first;
}
N--;
return item;
}
}
测试用例
Application.java
package myqueue.chainqueue;
public class Application {
public static void main(String[] args) {
String[] tobe = "to be or not to - be - - that - - - is".split(" ");
ChainQueue<String> stringChainQueue = new ChainQueue<>();
for (String s : tobe) {
if (!s.equals("-")) {
stringChainQueue.enQueue(s);
} else if (!stringChainQueue.isEmpty()) {
System.out.print(stringChainQueue.deQueue() + " ");
}
}
System.out.println("(" + stringChainQueue.size() + " left on queue)");
for (String s : stringChainQueue) {
System.out.print(s + " ");
}
}
}
输出
to be or not to be (2 left on queue)
that is
记忆点
依然是迭代器,实现 Iterator
private class ChainQueueIterator implements Iterator<T> {// 不是泛型类
private Node firstI = first;
//private Node lastI = last;
@Override
public void remove() {
}
@Override
public boolean hasNext() {
return firstI != null;// 正确的 hasNext 条件
}
@Override
public T next() {
T itemI = firstI.item;
firstI = firstI.next;
return itemI;
}
}
背包 - 链表实现
接口
BagInterface.java
package chain.bag;
public interface BagInterface<T> {
void add(T t);
boolean isEmpty();
int size();
}
背包类
Bag.java
package chain.bag;
import java.util.Iterator;
public class Bag<T> implements BagInterface<T>, Iterable<T>{
private class BagIterator implements Iterator<T> {
Node checkPoint = first;
@Override
public void remove() {
}
@Override
public boolean hasNext() {
return checkPoint != null;
}
@Override
public T next() {
T checkItem = checkPoint.item;
checkPoint = checkPoint.next;
return checkItem;
}
}
@Override
public Iterator<T> iterator() {
return new BagIterator();
}
private class Node {
T item;
Node next;
}
private Node first;
private int N;
@Override
public void add(T t) {
Node oldFirst = first;
first = new Node();
first.item = t;
first.next = oldFirst;
N++;
}
@Override
public boolean isEmpty() {
return N == 0;
}
@Override
public int size() {
return N;
}
}
测试用例
Application.java
package chain.bag;
public class Application {
public static void main(String[] args) {
String[] tobe = "to be or not to - be - - that - - - is".split(" ");
Bag<String> stringBag = new Bag<>();
for (String s : tobe) {
stringBag.add(s);
}
System.out.println(stringBag.isEmpty());
System.out.println(stringBag.size());
for (String s : stringBag) {
System.out.print(s + " ");
}
}
}
输出
false
14
is - - - that - - be - to not or be to
记忆点
无