Stack/Set/Map/Queue浅析

来源:互联网 发布:linux curl 请求url 编辑:程序博客网 时间:2024/06/09 17:57

“栈”通常是表示“后进先出”的容器。就好比在盘子里叠入披萨,最后放进去的总是在最上面。ListkedList具有能直接实现栈的所有功能的方法,因此可以直接将LinkedList当作栈使用。不过,有时候一个真正的“栈”更能把事情说明白:
import java.util.LinkedList;public class Stack<T>{    private LinkedList<T> storage = new LinkedList<T>();    public void push(T v){        storage.addFirst(v);    }    public T peek(){        return storage.getFirst();    }    public T pop(){        return storage.removeFirst();    }    public boolean empty(){        return storage.isEmpty();    }    public String toString(){        return storage.toString();    }}
这里使用泛型,引入了在栈的类定义中最简单的可行示例。T表示告诉编译器这是参数化的类型,实际类型会在使用时被替换。如果我们只需要栈的行为,那使用继承就不合适了,因为这样就会产生具有LinkedList的其他所有方法的类。
public static void main(String[] args) {    //创建具有泛型T的Stack类。并声明了T为String类型    Stack<String> stack = new Stack<String>();    for(String s : "My dog has fleas".split(" ")){        stack.push(s);    }    while (!stack.empty()) {        //pop()方法是移除栈顶元素,并且返回。        System.out.println(stack.pop() + " ");    }}

Set

Set不保存重复元素。如果我们需要查询功能,那么用hashSet是很好的选择,因为它专门针对了查找进行优化。Set和Collection有完全一样的接口。实际上Set就是Collection,只是行为不同。行为的不同是继承和多态的典型应用。Set是基于对象的值来确定归属的。
public static void main(String[] args) {        Random rand = new Random(47);        Set<Integer> intset = new HashSet<Integer>();        for(int i = 0; i < 10000; i++){            intset.add(rand.nextInt(30));        }        System.out.println(intset);    }//out[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
在hashSet中插入了0-29的10000个随机数,但是实际结果只有0-29,并且是无序的。这里的无序指的是存入和取出的顺序不一致。因为考虑到速度原因,HashSet用到了散列。其顺序与TreeSet和LinkedHashSet都不同,因为他们的实现具有不同的元素存储方式。TreeSet将元素存储在红-黑树数据结构中,而HashSet是散列函数。LinkedHashSet也使用了散列,但是看起来它使用了链表来维护插入顺序。如果我们需要排序,可以用TreeSet来替换HashSet,默认安装字典排序,并且区分大小写。如果想用字母排序,可以向TreeSet构造器传入String.CASE_INSENTIVE_ORDER
public static void main(String[] args) {        String sort = "A B C J Y O M G M U O aa b c j y o m g m u o";        Set<String> words = new TreeSet<String>();        for(String s : sort.split(" ")){            words.add(s);        }        System.out.println("not set para:" + words);        Set<String> words2 = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);        for(String s : sort.split(" ")){            words2.add(s);        }        System.out.println("use set para:" + words2);    }//out not set para:[A, B, C, G, J, M, O, U, Y, a, b, c, g, j, m, o, u, y]use set para:[A, aa, B, C, G, J, M, O, U, Y]
很明显String.CASE_INSENSITIVE_ORDER虽然是按照字符排序了,但是其实际含义是不区分大小写。也就是B和b只能在Set中存在一个了。

Map

将对象映射到其他对象的能力是一种解决编程问题的杀手锏。
public static void main(String[] args) {        Random rand = new Random(47);        Map<Integer, Integer> m = new HashMap<>();        for(int i = 0; i < 10000; i++){            int r = rand.nextInt(20);            Integer freq = m.get(r);            m.put(r, freq == null ? 1:freq+1);        }        System.out.println(m);    }//out{0=481, 1=502, 2=489, 3=508, 4=481, 5=503, 6=519, 7=471, 8=468, 9=549, 10=513, 11=531, 12=521, 13=506, 14=477, 15=497, 16=533, 17=509, 18=478, 19=464}
自动包装机制,将随机生成的int转换成了Integer类型,用生成的int类型去Map中找,是否有该key,如果没有会返回null,如果有则会返回对应的value值。为null的情况会赋值给freq为1,不为null就进行累加。在累加中,自动拆包又进行的操作,否则Integer不能进行累加的。

Map与数组和其他的Collection一样。可以很简单的扩展到多维结果,比如Map<Stirng,Map<Integer,String>>或者更复杂的数据结构。
//这句话表示,该变量petPeople的数据类型是Map,而Map中key是String,value是List。这个List的类型是未知但且继承String    public static Map<String,List<? extends String>> petPeople = new HashMap<>();    static{        petPeople.put("Dawn", Arrays.asList("Molly","Spot"));        petPeople.put("Kata", Arrays.asList("Shackleton","Elsie May","Margrett"));        petPeople.put("Marilyn", Arrays.asList("Louie aka Louis Snorkelstein Dupree",                "Stanford aka Srinky el Negro",                "Pinkola"));        petPeople.put("Luke", Arrays.asList("Fuzzy","Fizzy"));        petPeople.put("Isaac", Arrays.asList("Freckly"));    }    public static void main(String[] args) {        //keySet返回了所有key组成的Set        System.out.println("People: " + petPeople.keySet());        //values返回了所有对应的value,根据Set的默认排序        System.out.println("Pets: " + petPeople.values());        for (String string : petPeople.keySet()) {            System.out.println(string + " has:");            for (String s : petPeople.get(string)) {                System.out.println("   " + s);            }        }    }

Queue

队列是保持先进先出,和LinkedList相反。就像排队打饭一样,先排队的人,就能先打到饭,排除插队的情况。队列在并发编程中特别重要,因为它们可以安全地将对象从一个任务传给另一个任务。LinkedList提供了方法以支持队列的行为,并且它是想了Queue接口,因此LinkedList可以用做Queue的一种实现。通过将LinkedList向上转型为Queue。
public static void printQ(Queue queue){        while(queue.peek() != null){            System.out.print(queue.remove() + " ");        }    }    public static void main(String[] args) {        Queue<Integer> queue = new LinkedList<>();        Random rand = new Random(47);        for (int i = 0; i < 10; i++) {            queue.offer(rand.nextInt(i+10));        }        printQ(queue);    }
offer()将一个元素插入到队列尾端。在将LinkedList转化为Queue后,LinkedList的方法会不能使用。当然我们可以将Queue又转成LinkedList。

PriorityQueue

PriorityQueue在Java SE5中被添加,是为了提供这种行为的一种自动实现。当你在PriorityQueue上调用offer()方法来插入一个对象时,这个对象会在队列中被排序。默认的排序将使用对象在队列中的自然顺序,但是你可以通过提供自己的Comparator来修改这个顺序。PriorityQueue可以确保当你在调用Peel(),poll()和remove()时,获取的是最高优先级的元素。
public static void printQ(Queue queue){        while(queue.peek() != null){            System.out.print(queue.remove() + " ");        }        System.out.println();    }    public static void main(String[] args) {        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();        Random rand = new Random(47);        for (int i = 0; i < 10; i++) {            //队列存值            priorityQueue.offer(rand.nextInt(i + 10));        }        //输出第一次删除被返回的值        PriorityQueueDemo.printQ(priorityQueue);        //构建ints的List容器。此种构建方式,不允许被add        List<Integer> ints = Arrays.asList(25,22,20,18,14,9,3,1,1,2,3,9,14,18,21,23,25);        //将此List给优先级队列        priorityQueue = new PriorityQueue<>(ints);        PriorityQueueDemo.printQ(priorityQueue);        priorityQueue = new PriorityQueue<>(ints.size(),Collections.reverseOrder());        priorityQueue.addAll(ints);        PriorityQueueDemo.printQ(priorityQueue);    }
由此可以看出,队列运行重复,数字小的优先级高(比字母高)。大写字母比小写字母优先级高。Collections.reverseOrder()同样是在JAVA SE5中增加的反序Comparator。

下节会讲Collection和Iterator和Foreach和适配器方法惯用法

阅读全文
0 0