背包、队列和栈

API介绍


背包

public class Bag<Item> implements Iterable<Item>
{
            Bag()              // 创建一个空背包
    void    add(Item item)     // 向背包中添加一个元素
    boolean isEmpty()          // 背包是否为空
    int     size()             // 背包中的元素数量
}         

队列

public class Queue<Item> implements Iterable<Item>
{
            Queue()            // 创建空队列
    void    enqueue(Item item) // 添加一个元素
    Item    dequeue()          // 删除最早添加的元素
    boolean isEmpty()          // 队列是否为空
    int     size()             // 队列中的元素数量
}

public class Stack<Item> implements Iterable<Item>
{
            Stack()             // 创建一个空栈
    void    push(Item item)     // 压入一个元素
    Item    pop()               // 推出最后压入的元素
    boolean isEmpty()           // 栈是否为空
    int     size()              // 栈中的元素数量
}

特点及用例


背包

  • 不支持从中删除元素
  • 迭代的顺序不确定且与用例无关
// 用于计算平均数和标准差
public class Stats
{
    public static void main(String[] args)
    {
        Bag<Double> numbers = new Bag<Double>();
        while (!StdIn.isEmpty())
            numbers.add(StdIn.readDouble());
        int N = numbers.size();

        double sum = 0.0;
        for (double x : numbers)
            sum += x;
        double mean = sum/N;  // 平均数

        sum = 0.0;
        for (double x : numbers)
            sum += (x - mean)*(x - mean);
        double std = Math.sqrt(sum/(N-1));  // 标准差

        StdOut.printf("Mean: %.2f\n", mean);
        StdOut.printf("Std: %.2f\n", std);
    }
}

队列

  • 先进先出(FIFO)
  • 入列顺序和出列顺序相同
// 将队列的中数字拷贝到数组当中
public static int[] readInts(String name)
{
    In in = new In(name);
    Queue<Integer> q = new Queue<Integer>();
    while (!in.isEmpty())
        q.enqueue(in.readInt()); // 从文件中读入整数, 加入队列(自动装箱)

    int N = q.size();
    int[] a = new int[N];  // 数组定义初始化
    for (int i = 0; i < N; i++)
        a[i] = q.dequeue();  // FIFO: 顺序保持不变
    return a;
}

  • 后进先出(LIFO)
  • 可是使用双栈来求解数学运算
public class Evaluate
{
    public static void main(String[] args)
    {
        Stack<String> ops = new Stack<String>();  // 操作符栈
        Stack<Double> vals = new Stack<Double>();  // 操作数栈
        while (!StdIn.isEmpty())
        {
            String s = StdIn.readString();
            if      (s.equals("("));
            else if (s.equals("+"))      ops.push(s);
            else if (s.equals("-"))      ops.push(s);
            else if (s.equals("*"))      ops.push(s);
            else if (s.equals("/"))      ops.push(s);
            else if (s.equals(")"))
            {
                String op = ops.pop();  // 弹出操作符
                double v  = vals.pop(); // 弹出操作数
                if      (op.equals("+")) v = vals.pop() + v;  
                else if (op.equals("-")) v = vals.pop() - v;  
                else if (op.equals("*")) v = vals.pop() * v;
                else if (op.equals("/")) v = vals.pop() / v;
                vals.push(v);
            }
            else vals.push(Double.parseDouble(s));
        }
        StdOut.println(vals.pop());
    }
}

集合类数据类型的实现


动态变容量的栈(数组实现)

  1. 需要resize方法动态扩展栈的容量
  2. push的时候,需要检查栈和数组的大小,合适的时候进行扩容
  3. pop的时候,当栈的大小小于数组的1/4的时候,数组缩减为原来的1/2
  4. pop的时候,将不使用的对象置为null,方便垃圾回收
  5. 实现iterable接口,方便遍历
import java.util.Iterator
public class ResizeingArrayStack<Item> implements Iterable<Item> {
  private Item[] a = (Item[]) new Object[1]; // 栈元素  
  private int N = 0; // 元素数量  
  public boolean isEmpty() {return N == 0;}
  public int size() {return N;}
  private void resize(int max) {
    // 将一个数组移动到一个新的数组当中
    Item[] temp = (Item[]) new Object[max];
    for (int i = 0; i < N; i++)
      temp[i] = a[i];
    a = temp;
  }

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

  public Item pop() {
    Item item = a[--N];
    a[N] = null;// 避免对象游离
    if (N > 0 &&N < a.length / 4) 
      resize(a.length / 2);
  }
 
  public Iterator<Item> iterator() {
    return new ReverseArrayIterator()
  }

  private class ReverseArrayIterator implements Iterator<Item>{
    // 实现后进先出的迭代顺序
    private int i = N;
    public boolean hasNext() { return N > 0; }
    public Item next() { return a[--i]; }
    public void remove() {}
  }
} 

动态变容量的栈(链表实现)

import java.util.Iterator
public class Stack<Item> implements Iterable<Item> {
    private Node first;
    private int N;
    private class Node {
        Item item;
        Node next;
    }
    
    public boolean isEmpty(){
        return N == 0;
    }
    
    public int size() {
        return N;
    }
    
    public void push(Item item) {
        Node oldFirst = first;
        first = new Node();
        first.item = item;
        first.next = oldFirst;
        N++;
    }
    
    public Item pop() {
        Item item = first.item;
        first = first.next;
        N--;
        return item;
    }
}

动态变容量的队列(链表实现)

由于实现队列需要使用两个指针(first/last), 所以需要考虑一些特殊情况。

  1. 入队列的时候,如果只有一个元素,需要将first和last都指向第一个元素
  2. 出队列的时候,如果是最后一个元素,需要将last置为null
import java.util.Iterator
public class Queue<Item> implements Iterable<Item> {
    private Node first;
    private Node last;
        private int N;
    private class Node {
        Item item;
        Node next;
    }
    
    public boolean isEmpty(){
        return N == 0;
    }
    
    public int size() {
        return N;
    }
    
    public void enqueue(Item item) {
        Node oldLast = last;
        last = new Node();
        last.item = item;
        last.next = null;
        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;
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,417评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,921评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,850评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,945评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,069评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,188评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,239评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,994评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,409评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,735评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,898评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,578评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,205评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,916评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,156评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,722评论 2 363
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,781评论 2 351

推荐阅读更多精彩内容