Tod4の 代码零碎.|

Tod4

园龄:2年11个月粉丝:21关注:0

【数据结构与算法】背包、队列和栈

前言

集合类数据类型的实现

1 栈

1.1 定容栈
/**
* 定容栈的实现
*
*/
public class FixedCapacityStackOfStrings {
private String[] a;
private int N = 0;
public FixedCapacityStackOfStrings(int capacity) {
a = new String[capacity];
}
public int size() {
return N;
}
public boolean isEmpty() {
return N == 0;
}
public void push(String item) {
a[N++] = item;
}
public String pop() {
return a[--N];
}
// 测试
public static void main(String[] args) {
String str = "to be or not to - be - - that - - - is";
String expect = "to be not that or be ";
String result = "";
FixedCapacityStackOfStrings s = new FixedCapacityStackOfStrings(100);
for(String item : str.split(" ")) {
if(!"-".equals(item)) {
s.push(item);
}
else if(!s.isEmpty()) {
result += s.pop() + " ";
}
}
System.out.println(expect.equals(result));
}
}
1.2 泛型定容栈
/**
* 泛型定容栈
*/
public class FixedCapacityStack<Item> {
private Item[] a;
private int N = 0;
public FixedCapacityStack(int capacity) {
// 不能使用泛型数组
a = (Item[]) new Object[capacity];
}
public boolean isEmpty() {
return N == 0;
}
public Item pop() {
return a[--N];
}
public void push(Item item) {
a[N++] = item;
}
public int size() {
return N;
}
// 测试
public static void main(String[] args) {
String str = "to be or not to - be - - that - - - is";
String expect = "to be not that or be ";
String result = "";
FixedCapacityStack<String> s = new FixedCapacityStack<>(100);
for(String item : str.split(" ")) {
if(!"-".equals(item)) {
s.push(item);
}
else if(!s.isEmpty()) {
result += s.pop() + " ";
}
}
System.out.println(expect.equals(result));
}
}

需要注意的是,上面代码中泛型定容栈的初始化使用的是:

a = (Item[]) new Object[capacity];

而不是:

a = new Item[capacity];

这是由于创建泛型数组在Java中是不允许的

1.3 调整数组的大小:实现Stack API动态改变数组大小

选择用数组表示栈内容意味着用例必须预先估计栈的最大容量。在Java中,数组一旦被声明长度就不能够再进行更改了,选择大容量的用例在栈为空时会造成内存的极大浪费。同时在push的时候还需要考虑栈满的情况,综合上面两点,书中提供了一种解决方法:即使用一个大小不同的数组对栈进行转移:

public void resize(int max) {
Item[] temp = (Item[]) new Object[max];
for(int i=0;i<N;i++) {
temp[i] = a[i];
}
a = temp;
}

如此一来,就可以在push操作之前pop操作之后判断栈的容量,以动态改变栈数组的大小。

public void push(Item item) {
if(N == a.length)
resize(a.length * 2);
a[N++] = item;
}
public Item pop() {
Item item = a[--N];
// 防止对象游离
a[N] = null;
// N=0不必再进行长度缩减
if(N > 0 && N <= a.length/4)
resize(a.length / 2);
return item;
}

这里解决了栈满的判定问题,但是栈空pop时还需要进行判定

对象游离:

Java的垃圾回收策略是回收所有无法被访问到的对象的内存;但是像栈被pop出的元素,它是永远不可能被访问到的了,但是仍然存在于内存,但是Java的垃圾回收器没有办法知道这一点,因此需要通过引用覆盖的方式告知:

a[N] = null

1.4 实现Stack API的迭代

Java集合类型数据类型的基本操作之一就是能够通过for-each语句进行遍历元素,原因是因为Collection类实现了Iterable接口:

public interface Collection<E> extends Iterable<E>

Iterable接口维护了一个Iterator迭代器接口,接口方法用于定义迭代的规则,迭代器接口方法包括:

public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}

因此要实现Stack API的迭代,需要API implement Iterable<Item>和添加它的方法iterator:

@Override
public Iterator iterator() {
return new ReverseArrayIterator();
}

ReverseArrayIterator实现了Iterator接口,定义了迭代需要的hashNext和next接口方法:

private class ReverseArrayIterator implements Iterator<Item> {
private int i = N;
@Override
public boolean hasNext() {
return i > 0;
}
@Override
public Item next() {
return a[--i];
}
@Override
public void remove() {
}
}

ReverseArrayIterator为定义在Stack的内部类

1.5 综合:一个能够动态调整数组大小并且能够进行迭代的Stack API
package Algorithms.One;
import java.util.Collection;
import java.util.Iterator;
public class IterableStack<Item> implements Iterable<Item>{
private Item[] a;
//默认初始化为0
private int N;
public void resize(int max) {
Item[] temp = (Item[]) new Object[max];
for(int i=0;i<N;i++) {
temp[i] = a[i];
}
a = temp;
}
public IterableStack(int capacity) {
a = (Item[]) new Object[capacity];
}
public void push(Item item) {
if(N == a.length)
resize(a.length * 2);
a[N++] = item;
}
public Item pop() {
Item item = a[--N];
// 防止对象游离
a[N] = null;
// N=0不必再进行长度缩减
if(N > 0 && N <= a.length/4)
resize(a.length / 2);
return item;
}
public boolean isEmpty() {
return N == 0;
}
@Override
public Iterator iterator() {
return new ReverseArrayIterator();
}
private class ReverseArrayIterator implements Iterator<Item> {
private int i = N;
@Override
public boolean hasNext() {
return i > 0;
}
@Override
public Item next() {
return a[--i];
}
@Override
public void remove() {
}
}
public static void main(String[] args) {
String str = "to be or not to - be - - that - - - is";
String expect = "to be not that or be ";
String result = "";
IterableStack<String> s = new IterableStack<>(100);
for(String item : str.split(" ")) {
if(!"-".equals(item)) {
s.push(item);
}
else if(!s.isEmpty()) {
result += s.pop() + " ";
}
}
System.out.println(expect.equals(result));
Iterator iterator = s.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
for (String str2 : s) {
System.out.println(str2);
}
}
}

2 链表

链表是一种递归的线性数据结构,它或为空(null),或者是指向一个节点(node)的引用,该节点包含一个泛型的元素和一个指向另一条链表的引用。

public class LinkedList<Item> {
private class Node {
Item item;
Node next;
}
}
private Node first;

在需要使用Node类的类中将其定义为私有的内部类,因为它不是为用例准备的(书中这句话我的理解是它的数据类型随用例类LinkedList变化而不是自己能够决定,每个用例都可以这么写,不是单独为用每个例准备的)

2.1 在表头插入节点
/**
* 在表头插入节点
* @param item
*/
private void addOnHead(Item item) {
Node temp = new Node();
temp.item = item;
temp.next = first.next;
first = temp;
}
2.2 从表头删除节点
/**
* 在表头删除节点
* @return
*/
private boolean deleteAtHead() {
// 没有节点删除失败
if(first == null)
return false;
// 有一个节点,将链表置空
if(first.next == null)
first = null;
// 两个以上节点的情况
else
first.next = first.next.next;
return true;
}
2.3 在表尾插入节点
/**
* 尾插法
* @param item
*/
public void insertOnTail(Item item) {
Node temp = new Node();
temp.item = item;
Node tail = first;
if(tail==null) {
tail = temp;
}
while(tail.next!=null) {
tail = tail.next;
}
tail.next = temp;
}
2.5 链栈LinkedStack的实现

链栈即为使用链表实现的栈,栈的顶部即为表头,实例变量first指向栈顶,这样当使用push的时候将元素添加到表头,pop的时候将表头元素删除即可,使用一个变量N计数元素个数,并且实现了Iterable使得链栈可以使用for-each进行遍历,链表的使用完美达到了栈的最优设计目标:

① 可以存储任意数据类型的数据

② 所需的空间总是和集合大小成正比,且大小不被限制(硬件允许的条件下)

③ 操作所需时间和集合大小无关

④ 可以进行for-each遍历

public class LinkedStack<Item> implements Iterable<Item> {
private class Node {
Item item;
Node next;
}
private Node first;
private int N;
public void push(Item item) {
Node oldFirst = first;
first = new Node();
first.item = item;
first.next = oldFirst;
N++;
}
public Item pop() {
if(first == null)
return null;
Item item = first.item;
first = first.next;
N--;
return item;
}
public int size() {
return N;
}
public boolean isEmpty() {
return N == 0;
}
@Override
public Iterator<Item> iterator() {
return new LinkedStackIterator();
}
private class LinkedStackIterator implements Iterator<Item>{
private int i = N;
@Override
public boolean hasNext() {
return i > 0;
}
@Override
public Item next() {
Node temp = first;
for(int j=0;j<i-1;j++)
temp = temp.next;
i--;
return temp.item;
}
}
// 测试
public static void main(String[] args) {
LinkedStack<Integer> stack = new LinkedStack<>();
for (int i=0;i<10;i++)
stack.push(i);
System.out.println(stack.pop());
for(int val : stack) {
System.out.print(val);
}
}
}
2.6 链式队列LinkedQueue的实现

将队列表示为一条最早插入到最近插入的链表,实例变量first指向队列的队首,tail指向队尾,入队enQueue将添加元素添加到表尾,出队deQueue操作将元素添加到表首。

package Algorithms.One;
import java.util.Iterator;
public class LinkedQueue<Item> implements Iterable<Item> {
private class Node {
Item item;
Node next;
}
private int N;
private Node first;
private Node tail;
// 表尾入队
public void enQueue(Item item) {
Node oldTail = tail;
tail = new Node();
tail.item = item;
if(N == 0)
first = tail;
else
oldTail.next = tail;
N++;
}
// 表首出队
public Item deQueue() {
if(first == null)
return null;
Item item = first.item;
first = first.next;
if(isEmpty()) tail=null;
N--;
return item;
}
public boolean isEmpty() {
return N == 0;
}
public int size() {
return N;
}
private void printAll() {
Node temp = first;
while(first!=null) {
System.out.println(first.item);
first = first.next;
}
}
@Override
public Iterator<Item> iterator() {
return new LinkedQueueIterator();
}
private class LinkedQueueIterator implements Iterator<Item> {
private int i = 0;
@Override
public boolean hasNext() {
return i<N;
}
@Override
public Item next() {
Node temp = first;
for(int j=0;j<i;j++)
temp = temp.next;
i++;
return temp.item;
}
}
public static void main(String[] args) {
LinkedQueue<Integer> queue = new LinkedQueue<>();
for(int i=0;i<10;i++)
queue.enQueue(i);
for(int var:queue) {
System.out.print(var);
}
}
}
posted @   Tod4  阅读(43)  评论(0编辑  收藏  举报
   
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起