Coursare·Algorithms, Part I第二週作業

本週作業是相比較第一週要簡單一些,主要寫一個雙端隊列(Deque)和一個隨機隊列(Randomized Queue)以及一個客戶端(Permutation)

Deque

要求:
A double-ended queue or deque (pronounced “deck”) is a generalization of a stack and a queue that supports adding and removing items from either the front or the back of the data structure. Create a generic data type Deque that implements the following API:
Deque API

異常:

  • Throw a java.lang.IllegalArgumentException if the client calls either
    addFirst() or addLast() with a null argument.
  • Throw a java.util.NoSuchElementException if the client calls either
    removeFirst() or removeLast when the deque is empty.
  • Throw a java.util.NoSuchElementException if the client calls the
    next() method in the iterator when there are no more items to return.
  • Throw a java.lang.UnsupportedOperationException if the client calls
    the remove() method in the iterator.

性能:
Your deque implementation must support each deque operation (including construction) in constant worst-case time. A deque containing n items must use at most 48n + 192 bytes of memory and use space proportional to the number of items currently in the deque. Additionally, your iterator implementation must support each operation (including construction) in constant worst-case time.

內容:
寫一個雙端鏈表,至少包含上面api給出的方法,在最惡劣的情況下,n個數據時最多使用 48n+192 個字節,因爲可以在隊頭插入和刪除數據,所以我選擇用鏈表構成

import java.util.Iterator;
import java.util.NoSuchElementException;


public class Deque<Item> implements Iterable<Item> {
    private Node first;
    private Node last;
    private int size;

    private class Node {
        Item node;
        Node next;  // 下一節點
        Node pre;       // 上一節點
    }

    public Deque() {
        first = null;
        last = null;
        size = 0;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public void addFirst(Item item) {
        if (item == null) {
            throw new IllegalArgumentException();
        }
        // 將數據插入頭部
        Node oldNode = first;
        first = new Node();
        first.node = item;
        first.next = oldNode;
        // 判斷是否爲空,爲空的話尾節點指向頭結點數據,不爲空將原頭節點的上一節點指向新建頭結點
        if (isEmpty()) {
            last = first;
        } else {
            oldNode.pre = first;
        }
        // 數量+1
        size++;
    }

    public void addLast(Item item) {
        if (item == null) {
            throw new IllegalArgumentException();
        }
        Node oldNode = last;
        last = new Node();
        last.node = item;
        last.pre = oldNode;
        if (isEmpty()) {
            first = last;
        } else {
            oldNode.next = last;
        }
        size++;
    }

    public Item removeFirst() {
        Node oldNode = first;
        if (isEmpty()) {
            throw new NoSuchElementException();
        } else if (first != last) {
            // 當頭結點和尾節點不是同一節點時,將下一個頭結點的上一節點設置爲null
            first.next.pre = null;
        }
        first = first.next;
        size--;
        return oldNode.node;
    }

    public Item removeLast() {
        Node oldNode = last;
        if (isEmpty()) {
            throw new NoSuchElementException();
        } else if (first != last) {
            // 當頭結點和尾節點不是同一節點時,將下一個尾結點的下一節點設置爲null
            last.pre.next = null;
        }
        last = last.pre;
        size--;
        return oldNode.node;
    }

    public int size() {
        return size;
    }

    @Override
    public Iterator<Item> iterator() {
        return new MyIterator();
    }

    private class MyIterator implements Iterator<Item> {
        private Node current = first;

        @Override
        public boolean hasNext() {
            return current != null;
        }

        @Override
        public Item next() {
            if (!hasNext()) {
                throw new NoSuchElementException();
            }
            Node oldNode = current;
            current = current.next;
            return oldNode.node;
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }
    }

    public static void main(String[] args) {
        Deque<Integer> deque = new Deque<Integer>();
        deque.addLast(1);
        System.out.println(deque.removeFirst());
        deque.addFirst(3);
        System.out.println(deque.removeLast());
    }
}

Randomized Queue

要求:
A randomized queue is similar to a stack or queue, except that the item removed is chosen uniformly at random from items in the data structure. Create a generic data type RandomizedQueue that implements the following API:
Randomized Queue API
異常:

  • Throw a java.lang.IllegalArgumentException if the client calls enqueue() with a null argument.
  • Throw a java.util.NoSuchElementException if the client calls either sample() or dequeue() when the randomized queue is empty.
  • Throw a java.util.NoSuchElementException if the client calls the next() method in the iterator when there are no more items to return.
  • Throw a java.lang.UnsupportedOperationException if the client calls the remove() method in the iterator.

性能:
Your randomized queue implementation must support each randomized queue operation (besides creating an iterator) in constant amortized time. That is, any sequence of m randomized queue operations (starting from an empty queue) must take at most cm steps in the worst case, for some constant c. A randomized queue containing n items must use at most 48n + 192 bytes of memory. Additionally, your iterator implementation must support operations next() and hasNext() in constant worst-case time; and construction in linear time; you may (and will need to) use a linear amount of extra memory per iterator.

內容:
寫一個隨機隊列,至少包含上面api給出的方法,在最惡劣的情況下,n個數據時最多使用 48n+192 個字節,每個iterator實例的遍歷順序是相對獨立的,而且是在線性時間內,基於此我選擇用數組來實現

import java.util.Iterator;
import java.util.NoSuchElementException;

import edu.princeton.cs.algs4.StdRandom;


public class RandomizedQueue<Item> implements Iterable<Item> {
    private Item[] item;
    private int size;

    public RandomizedQueue() {
        item = (Item[]) new Object[8];
        size = 0;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public int size() {
        return size;
    }

    public void enqueue(Item item) {
        if (size >= this.item.length) {
            resize(this.item.length * 2);
        }

        if (item == null) {
            throw new IllegalArgumentException();
        }
        this.item[size++] = item;
    }

    public Item dequeue() {
        if (isEmpty()) {
            throw new NoSuchElementException();
        }
        int n = StdRandom.uniform(0, size);
        Item tempItem = item[n];
        // 將數組n之後的數前移
        for (int i = n; i < size - 1; i++) {
            item[i] = item[i+1];
        }
        size--;
        // 判斷大小,並調整大小
        if (size < item.length/4) {
            resize(item.length/2);
        }
        return tempItem;
    }

    public Item sample() {
        if (isEmpty()) {
            throw new NoSuchElementException();
        }
        int n = StdRandom.uniform(0, size);
        return item[n];
    }

    private void resize(int capacity) {
        Item[] temp = (Item[]) new Object[capacity];
        for (int i = 0; i < size; i++) {
            temp[i] = item[i];
        }
        item = temp;
    }

    @Override
    public Iterator<Item> iterator() {
        return new MyIterator();
    }

    private class MyIterator implements Iterator<Item> {
        private final int[] n = StdRandom.permutation(size);
        private int current = 0;

        @Override
        public boolean hasNext() {
            return current != n.length;
        }

        @Override
        public Item next() {
            if (!hasNext()) {
                throw new NoSuchElementException();
            }

            return item[n[current++]];
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }

    }

    public static void main(String[] args) {
        RandomizedQueue<String> rq = new RandomizedQueue<String>();

        for (int i = 0; i < 10; i++) {
            rq.enqueue("第" + i + "個");
        }
        for (int i = 0; i < 10; i++) {
            System.out.println(rq.sample());
        }
        System.out.println("----------------------------------------");
        Iterator<String> iter = rq.iterator();
        while (iter.hasNext()) {
            System.out.println(iter.next());
        }
        System.out.println("----------------------------------------");
        Iterator<String> iter1 = rq.iterator();
        while (iter1.hasNext()) {
            System.out.println(iter1.next());
        }
        System.out.println("----------------------------------------");
        System.out.println(rq.dequeue());
    }
}

Permutation

要求:
Write a client program Permutation.java that takes an integer k as a command-line argument; reads in a sequence of strings from standard input using StdIn.readString(); and prints exactly k of them, uniformly at random. Print each item from the sequence at most once.
性能:
The running time of Permutation must be linear in the size of the input. You may use only a constant amount of memory plus either one Deque or RandomizedQueue object of maximum size at most n. (For an extra challenge, use only one Deque or RandomizedQueue object of maximum size at most k.)
分析:
因爲需要隨機輸出打印存入的數據,所以用RandomizedQueue比較好,這裏有一個挑戰,是讓選用的數據結構最大值是輸入的k,這裏我沒有完成,後續如果有什麼想法會及時更新

import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;


public class Permutation {
    public static void main(String[] args) {
        // 調用函數傳入的值k 
        int k = Integer.parseInt(args[0]);

        RandomizedQueue<String> rq = new RandomizedQueue<String>();
        while (!StdIn.isEmpty()) {
            rq.enqueue(StdIn.readString());
        }
        for (int i = 0; i < k; i++) {
            StdOut.println(rq.dequeue());
        }
    }
}

歡迎大家評論探討哦

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章