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

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()操作也是常数时间和常数空间,具体的要求如下。

所以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的内容对于理解和实现有很大帮助,那么我们可以这样设计:

使用哨兵指向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个元素就可以得到结果了。

Programming Assignment 2: Randomized Queues and Deques的更多相关文章

  1. AlgorithmsI PA2: Randomized Queues and Deques RandomizedQueue

    RandomizedQueue 有几个关键点: 1. 选择合适的数据结构,因为需要任意位置删除元素,Linked list 做不到,必须使用resizing arrays. 2. resizing 的 ...

  2. AlgorithmsI PA2: Randomized Queues and Deques Deque

    本次作业考察利用array 或者linked list 实现规定时间复杂度的queue 和stack, 不能使用java 自带的stack 和queue. 目的是让我们掌握自己设计的函数的复杂度. D ...

  3. AlgorithmsI PA2: Randomized Queues and Deques Subset

    本题的bonus是 因此方法是queue的size 达到了K, 就停止增加元素,保证queue.size() 最大时只有k. Java code: import edu.princeton.cs.al ...

  4. Programming Assignment 2: Deques and Randomized Queues

    编程作业二 作业链接:Deques and Randomized Queues & Checklist 我的代码:Deque.java & RandomizedQueue.java & ...

  5. 课程一(Neural Networks and Deep Learning),第三周(Shallow neural networks)—— 3.Programming Assignment : Planar data classification with a hidden layer

    Planar data classification with a hidden layer Welcome to the second programming exercise of the dee ...

  6. Algorithms: Design and Analysis, Part 1 - Programming Assignment #1

    自我总结: 1.编程的思维不够,虽然分析有哪些需要的函数,但是不能比较好的汇总整合 2.写代码能力,容易挫败感,经常有bug,很烦心,耐心不够好 题目: In this programming ass ...

  7. Algorithms : Programming Assignment 3: Pattern Recognition

    Programming Assignment 3: Pattern Recognition 1.题目重述 原题目:Programming Assignment 3: Pattern Recogniti ...

  8. Coursera Algorithms Programming Assignment 2: Deque and Randomized Queue (100分)

    作业原文:http://coursera.cs.princeton.edu/algs4/assignments/queues.html 这次作业与第一周作业相比,稍微简单一些.有三个编程练习:双端队列 ...

  9. Deques and Randomized Queues

    1. 题目重述 完成三个程序,分别是双向队列,随机队列,和随机队列读取文本并输出k个数. 2. 分析 2.1 双向队列 题目的性能要求是,操作时间O(1),内存占用最大48n+192byte. 当使用 ...

随机推荐

  1. sql 分组查询及格不及格人数

    select score as 类别,count(*) as 人数 from (select case when fen>=60 then '及格' else '不及格' end as scor ...

  2. jsp 错误码debug记录与总结

    500: 编码错误: 无法向cookie中写入中文字符串 需要使用URLEncoder.Encode()在写入处进行转码,使用URLDecoder.decoder()在读取处进行解码 或者使用requ ...

  3. winform客户端向web地址传参,怎样去接收参数。

    在web端定义js方法去接收客户端传递过来的参数,具体就是获取地址中?后的数据,各个参数用&分割,存储于数组中,获取. 具体如下: //定义获取地址中参数的方法 function GetReq ...

  4. weed-fs参数列表

    weed-fs没有详细的帮助文档,为了方便阅读,特意把有用的参数帮助罗列出来.未列出的两个命令为version(版本查询) 及shell(这个命令在0.45版本只有回显功能)nerc@Ubuntu:~ ...

  5. codeforces 360 C - NP-Hard Problem

    原题: Description Recently, Pari and Arya did some research about NP-Hard problems and they found the  ...

  6. socket编程相关的结构体和字节序转换、IP、PORT转换函数

    注意:结构体之间不能直接进行强制转换, 必须先转换成指针类型才可以进行结构体间的类型转换, 这里需要明确的定义就是什么才叫强制转换. 强制转换是将内存中一段代码以另一种不同类型的方式进行解读, 因此转 ...

  7. LoadRunner参数化详解(转)

    距离上次使用loadrunner 已经有一年多的时间了.初做测试时在项目中用过,后面项目中用不到,自己把重点放在了工具之外的东西上,认为性能测试不仅仅是会用工具,最近又想有一把好的利器毕竟可以帮助自己 ...

  8. Tornado sqlalchemy

    上篇文章提到了,最近在用 Python 做一个网站.除了 Tornado ,主要还用到了 SQLAlchemy.这篇就是介绍我在使用 SQLAlchemy 的过程中,学到的一些知识. 首先说下,由于最 ...

  9. 友盟分享SDK集成步骤

    1.官方注册appID. 2.menifest添加和声明umeng相关的activity以及appKey. 3. // 首先声明一个controller变量,由友盟服务工厂类直接取得友盟社交服务. m ...

  10. R--相关分布函数、统计函数的使用

    分布函数家族: *func()r : 随机分布函数d : 概率密度函数p : 累积分布函数q : 分位数函数 func()表示具体的名称如下表: 例子 #r : 随机分布函数 #d : 概率密度函数 ...