zoukankan      html  css  js  c++  java
  • Programming Assignment 2: Randomized Queues and Deques

    实现一个泛型的双端队列和随机化队列,用数组和链表的方式实现基本数据结构,主要介绍了泛型和迭代器。

     

    Dequeue. 实现一个双端队列,它是栈和队列的升级版,支持首尾两端的插入和删除。Deque的API如下

    public class Deque<Item> implements Iterable<Item> {
       public Deque()                           // construct an empty deque
       public boolean isEmpty()                 // is the deque empty?
       public int size()                        // return the number of items on the deque
       public void addFirst(Item item)          // insert the item at the front
       public void addLast(Item item)           // insert the item at the end
       public Item removeFirst()                // delete and return the item at the front
       public Item removeLast()                 // delete and return the item at the end
       public Iterator<Item> iterator()         // return an iterator over items in order from front to end
       public static void main(String[] args)   // unit testing
    }

    deque的操作实现必须是常数时间,使用空间是当前元素个数,迭代器的实现next()和hasNext()操作也是常数时间和常数空间,具体的要求如下。

    1

    所以Deque采用Linked-list实现方式。

    结点定义成:

    private class Node {
        private Item item;
        private Node prev;
        private Node next;
    }

    双端队列使用Linked-List实现,那么使用一个哨兵sentinel来辅助实现Deque,这在Programming Tricks and Common Pitfalls中有讲到,每个Assignment中checklist的内容对于理解和实现有很大帮助,那么我们可以这样设计:

    1

    使用哨兵指向deque的队首元素,而队尾元素指向哨兵,现在我们来分析每个方法实现。

    Deque(): 初始Deque没有元素,元素个数为0,那么哨兵的prev和next也都指向自身。

    addFirst(): 队首添加元素时候,就是简单的链表操作在sentinel和第一个Node之间插入一个新的Node,并记得把元素个数加1.

    addLast(): 同理

    removeFirst(): 首先要判断,deque是否为空,能否支持删除操作,可以的话,删除首元素,更新第二个元素和sentinel之间的关系,然后元素个数减1

    removeLast(): 同理

    isEmpty()和size(): 用一直维护元素个数变量来进行操作

    迭代器Iterator的操作也十分简单了, 我们只需要获取sentinel哨兵,然后遍历就可以实现。hasNext()直到下一个元素又走回了sentinel哨兵,那么我们就已经遍历完了所有元素。

    Randomized queue. 随机化队列也和栈和队列十分相似,区别在于它的remove操作是随机删除队列中的一个元素。API如下:

    public class RandomizedQueue<Item> implements Iterable<Item> {
       public RandomizedQueue()                 // construct an empty randomized queue
       public boolean isEmpty()                 // is the queue empty?
       public int size()                        // return the number of items on the queue
       public void enqueue(Item item)           // add the item
       public Item dequeue()                    // delete and return a random item
       public Item sample()                     // return (but do not delete) a random item
       public Iterator<Item> iterator()         // return an independent iterator over items in random order
       public static void main(String[] args)   // unit testing
    }

    时间和空间复杂度的要求看上面那个表格,我们使用Array数组的实现方式。注意一下java不能创建泛型数组,用cast强制转换来实现,但会导致warning

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

    Randomized queue和一般的queue基本操作都是一样,由于随机出队,那入队元素也不一定按照正常的队列来使用,我们只需要把队列的元素维护在连续起始开始的一段就可以了。

    那么我们只需要使用一个tail尾指针,当插入元素的时候,把元素直接插入在队尾:

    public void enqueue(Item item) {
        if (item == null)
            throw new java.lang.NullPointerException("can't add a null item");
        if (N == q.length) resize(2*q.length);
        q[tail++] = item;
        N++;
    }

    当出队的时候,随即一个1-元素个数之间的下标,删除这个元素,那么这个位置空出来怎么办?把队尾元素填充上去,然后队尾置为空。

    在入队和出队的时候,要进行resize操作维护空间大小,resize看PPT上面有讲解。

    public Item dequeue() {
        if (isEmpty())
            throw new java.util.NoSuchElementException("underflow");
        
        int index = StdRandom.uniform(N);
        Item item = q[index];
        //because random, just simply put q[tail-1] to q[index]
        q[index] = q[--tail];
        q[tail] = null;
        N--;
        if (N > 0 && N == q.length/4) resize(q.length/2);
        
        return item;
    }

    迭代器的操作,不能需改原来的元素,需要重新申请空间,随机化的出队思考起来也很简单,我们使用Elementary Sort中介绍的Shuffle的方法来对元素重新组合一下

    for (int i = 0; i < N; i++) {
        int r = StdRandom.uniform(i+1);
        Item tmp = array[i];
        array[i] = array[r];
        array[r] = tmp;
    }

     

    Subset client. 从n个string中随机输出k个,n中的所有元素每个最多只能输出一次。

    要求使用Deque或者RandomizedQueue空间复杂度最多为N,时间复杂度为N线性。

    使用RandomizedQueue实现的话,初始把所有N个元素都加入到队列中,然后dequeue()其中n-k个,然后输出剩下的k个元素就是结果了。

    使用Deque随机的把N个元素加入队首和队尾,接下来随机的在队首和队尾删除n-k元素,然后输出剩下的k个元素就可以得到结果了。

  • 相关阅读:
    浅涉OPC Client
    枚举目标机器已注册的OPC服务器
    C++ DCOM服务器和C#客户端互操作完全解释
    COMException:没有注册类别(REGDB_E_CLASSNOTREG)
    网络化广播主机ZABKZ/AXT8182
    OPC 技术文档之 IOPCBrowseServerAddressSpace 的使用
    SQL Server 2008 r2 服务无法启动
    Infinova V2040 系列 大型矩阵切换/控制系统
    COM中GUID和UUID、CLSID、IID
    django 视图与网址
  • 原文地址:https://www.cnblogs.com/tiny656/p/3821891.html
Copyright © 2011-2022 走看看