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());
        }
    }
}

欢迎大家评论探讨哦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值