抽象数据结构的实现 - 栈、队列、背包

抽象数据结构的手动实现

算法第四版

栈 - 长度可变

接口

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)

记忆点

  1. 类实现多个接口

    • 声明的时候多个接口用逗号隔开就行了

    • public class ResizeStack<T> implements StackInterface<T>, Iterable<T> {}
      
  2. 迭代器(以供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();
          }
      
      }
      
      
  3. 泛型数组

    • 假设泛型类型参数为<T>,类内创建a = new T[cap]; (cap是int)是不被允许的
    • 应使用一个IDEA报警告的方法:a = (T[]) new Object[cap];创建泛型数组
  4. 栈变长度

    • push时,若栈满,则扩充栈至原长度2倍
    • pop时,若栈的元素个数<栈长度/4,则缩短栈长度至原1/2
  5. 防止数组类型中值游离

    • 对于元素 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 

记忆点

posted @ 2021-12-19 19:50  jentreywang  阅读(76)  评论(0编辑  收藏  举报