• Algorithms 4th Reading Note(1:Foundation)


    1.定容栈

    public class StringArrayOfStack {
      private String[] stack;
      private int size;
      public StringArrayOfStack(int cap){
        stack=new String[cap];
        size=0;
      }
    
      public boolean isEmpty(){
        return size==0;
      }
    
      public int size(){
        return size;
      }
    
      public void push(String item){
        stack[size++]=item;
      }
    
      public String pop(){
        return stack[--size];
      }
    }

    2.泛型定容栈

    public class FixedCapacityStackOfStrings<Item> {
        private Item[] s;
        private int N = 0;
    
        @SuppressWarnings("unchecked")
        public FixedCapacityStackOfStrings(int capacity) {
            s = (Item[]) new Object[capacity];
        }
    
        public boolean isEmpty() {
            return N == 0;
        }
    
        public void push(Item item) {
            if (N == s.length) {
                resize(2 * s.length);
            }
            s[N++] = item;
        }
    
        public Item pop() {
            Item item = s[--N];
            s[N] = null;
            if (N == s.length / 4 && N > 0) {
                resize(s.length / 2);
            }
            return item;
        }
    
        public int size() {
            return N;
        }

      在这里有一个细节非常重要:我们希望用以上代码的构造函数的实现中创建一个泛型的数组:

    a=new Item[cap];

      由于某些历史和技术原因,创建泛型数组在Java中是不允许的。我们需要类型转换

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

      

    3.调整数组大小

      选择用数组表示栈内容意味着用例必须预先估计栈的最大容量。在Java中,数组一旦创建,其大小是无法改变的,因此栈使用的空间只能是这个最大容量的一部分。选择大容量的用例在栈为空或几乎为空时会浪费大量的内存。另一方面,如果集合变得比数组更大那么用例有可能溢出。

      动态调整数组s[]的大小,使得它既足以保存所有元素,又不至于浪费过多的空间。

      首先,实现一个方法讲栈移动到另一个大小不同的数组中

    public void resize(int Max) {
            Item[] item = (Item[]) new Object[Max];
            for (int i = 0; i < N; i++) {
                item[i] = s[i];
            }
            s = item;
        }

      现在,在push()中,检查数组是否太小。具体来说,我们会通过检查栈大小N和数组大小a.length是否想等来检查数组是否能够容纳新的元素。如果没有多余的空间,我们会将数组的长度加倍。然后就可以和从前一样使用s[N++]=item插入新元素了。

    public void push(Item item) {
            if (N == s.length) {
                resize(2 * s.length);
            }
            s[N++] = item;
        }

      类似,在pop()中,首先删除栈顶的元素,然后如果数组太大我们就将它的长度减半。只要稍加思考,你就明白正确的检测条件是栈大小是否小于数组的四分之一。在数组长度被减半之后,它的状态约为半满,在下次需要改变数组大小之前仍然能够进行多次push()和pop()操作

    public Item pop() {
            Item item = s[--N];
            s[N] = null;
            if (N == s.length / 4 && N > 0) {
                resize(s.length / 2);
            }
            return item;
        }

      在这个实现中,栈永远不会溢出,使用率也永远不会低于四分之一(除非栈为空,那种情况下数组的大小为1)

    4.迭代

      在任意可迭代的集合数据类型中我们都需要实现的东西:

      1)集合数据类型必须实现一个iterator()方法并返回一个Iterator对象。

      2)Iterator类必须包含两个方法:hasNext()(返回一个布尔值)和next()(返回集合中的一个泛型元素)。

      

      在Java中,我们使用接口机制来指定一个类所必须实现的方法。对于可迭代的集合数据类型,Java已经为我们定义了所需的接口。

      要使一个类可迭代,第一步就是在它的声明中加入implements Iterable<Item>,对应的接口为:

    public interface Iterable<Item>{
        Iterator<Item> iterator();
    }

      然后在类中添加一个方法iterator()并返回一个迭代器Iterator<Item>。迭代器都是泛型的,因此我们可以使用参数类型Item来帮助用例遍历它们指定的任意类型的对象。对于一直使用的数组表示法,我们需要逆序迭代遍历这个数组,因此我们将迭代器命名为ReverseArrayIterator,并添加方法:

    public Iterator<Item> iterator(){
        return new ReverseArrayIterator();
    }

      迭代器是什么?它是一个实现了hasNext()和next()方法的类的对象,由以下接口定义

    public interface Iterator<Item>{
        public boolean hasNext(){return i>0;}
        public Item next(){return a[--i];}
        public void remove(){ }
    }

      尽管接口指定了一个remove()方法,但在本书中remove()方法总为空,因为我们希望避免在迭代中穿插能够修改数据结构的操作。对于ReverseArrayIterator,这些方法只需要一行代码,它们实现在栈类的一个嵌套类中:

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

      请注意,嵌套类可以访问包含它的类的实例变量,在这里就是s[]和N(这也是我们使用嵌套类实现迭代器的主要原因)。从技术角度来说,为了和Iterator的结构保持一致,我们应该在两种情况下抛出异常:如果用例调用了remove()则抛出UnsupportedOperationException,如果用例在调用next()时i为0则抛出NoSuchElementException。因为我们只会在foreach语法中使用迭代器,这些情况都不会出现,所以我们省略了这部分代码

    5.链表

      使用一个嵌套类来定义结点的抽象数据类型

    private class Node{
        Item item;
        Node next;
    }

      链表的使用能达到三个设计目标:

      1)它可以处理任意类型的数据。

      2)所需的空间总是和集合的大小成正比。

      3)操作所需的时间总是和集合的大小无关。

      下压堆栈(链表实现)

    public class LinkedlistOfStack<Item> implements Iterable<Item> {
    
      private int size;
      private Node first;
    
      private class Node {
    
        Item item;
        Node next;
      }
    
      public boolean isEmpty() {
        return first == null;
      }
    
      public int size() {
        return size;
      }
    
      public void push(Item item) {
        Node old = first;
        first = new Node();
        first.item = item;
        first.next = old;
        size++;
      }
    
      public Item pop() {
        Item item = first.item;
        first = first.next;
        size--;
        return item;
      }
    
      public Iterator<Item> iterator() {
        return new ReverseStack();
      }
    
      private class ReverseStack implements Iterator<Item> {
    
        private Node pointer = first;
    
        public boolean hasNext() {
          return pointer != null;
        }
    
        public Item next() {
          Item item = pointer.item;
          pointer = pointer.next;
          return item;
        }
    
        public void remove() {
        }
      }
    }

      队列的实现

    public class LinkedQueueOfStrings<Item> implements Iterable<Item> {
        private Node first;
        private Node last;
        private int N;
    
        private class Node {
            Item item;
            Node next;
        }
    
        public boolean isEmpty() {
            return first == null;
        }
    
        public int size() {
            return N;
        }
    
        public void enqueue(Item item) {
            Node oldlast = new Node();
            last = new Node();
            last.item = item;
            if (isEmpty()) {
                first = last;
            } else {
                oldlast.next = last;
            }
            N++;
        }
    
        public Item dequeue() {
            Item item = first.item;
            first = first.next;
            if (isEmpty()) {
                last = null;
            }
            N--;
            return item;
        }
    
        public Iterator<Item> iterator() {
            return new ListIterator();
        }
    
        private class ListIterator implements Iterator<Item> {
            private Node current = first;
    
            public boolean hasNext() {
                return current != null;
            }
    
            public void remove() {
            }
    
            public Item next() {
                Item item = current.item;
                current = current.next;
                return item;
            }
        }
    }

      背包的实现

    public class Bag<Item> implements Iterable<Item> {
        private Node first;
    
        private class Node {
            Item item;
            Node next;
        }
    
        public void add(Item item) {
            Node oldfirst = first;
            first = new Node();
            first.item = item;
            first.next = oldfirst;
        }
    
        public Iterator<Item> iterator() {
            return new ListIterator();
        }
    
        private class ListIterator implements Iterator<Item> {
    
            private Node current = first;
    
            public boolean hasNext() {
                return current != null;
            }
    
            public void remove() {
            }
    
            public Item next() {
                Item item = current.item;
                current = current.next;
                return item;
            }
        }
    }

    6.union-find算法

      

  • 相关阅读:
    【动态规划】数的划分
    【动态规划】开心的小明
    【动态规划】回文字符串
    【动态规划】skiing_深度搜索_动态规划
    【动态规划】最大子串和
    JDBC中 execute 与 executeUpdate的区别
    poj 2449 Remmarguts' Date 求第k短路 Astar算法
    ACM-ICPC 2018 徐州赛区网络预赛 J. Maze Designer 最大生成树 lca
    hdu 2586 How far away ? 倍增求LCA
    acm模板生成
  • 原文地址:https://www.cnblogs.com/Miromiaosang/p/8542471.html
Copyright © 2020-2023  润新知