zoukankan      html  css  js  c++  java
  • 链表LinkedList、堆栈Stack、集合Set

    链表LinkedList

    在这里插入图片描述

    LinkedList 也像 ArrayList 一样实现了基本的 List 接口,但它在 List 中间执行插入和删除操作时比 ArrayList 更高效。然而,它在随机访问操作效率方面却要逊色一些。
    LinkedList 还添加了一些方法,使其可以被用作栈、队列或双端队列(deque) 。在这些方法中,有些彼此之间可能只是名称有些差异,或者只存在些许差异,以使得这些名字在特定用法的上下文环境中更加适用(特别是在 Queue 中)。例如:

    • getFirst() 和 element() 是相同的,它们都返回列表的头部(第一个元素)而并不删除它,如果 List 为空,则抛出 NoSuchElementException 异常。 peek() 方法与这两个方法只是稍有差异,它在列表为空时返回 null 。
    • removeFirst() 和 remove() 也是相同的,它们删除并返回列表的头部元素,并在列表为空时抛出 NoSuchElementException 异常。 poll() 稍有差异,它在列表为空时返回 null 。
    • addFirst() 在列表的开头插入一个元素。
    • offer() 与 add() 和 addLast() 相同。 它们都在列表的尾部(末尾)添加一个元素。
    • removeLast() 删除并返回列表的最后一个元素。
    /**
     * @author myf
     */
    public class LinkedListFeatures {
        public static void main(String[] args) {
            LinkedList<Fruits> fruitsList = new LinkedList<>();
            LinkedList<Fruits> nullList = new LinkedList<>();
            fruitsList.add(new Fruits("test"));
            fruitsList.add(new Fruits("apple"));
            fruitsList.add(new Fruits("orange"));
            fruitsList.add(new Fruits("banana"));
    
            // NoSuchElementException
            // System.out.println(nullList.getFirst());
            // System.out.println(nullList.element());
            // null
            System.out.println(nullList.peek());
            // Fruits{name='test'}
            System.out.println(fruitsList.getFirst());
            // Fruits{name='test'}
            System.out.println(fruitsList.element());
            // Fruits{name='test'}
            System.out.println(fruitsList.peek());
    
            // NoSuchElementException
            // System.out.println(nullList.removeFirst());
            // System.out.println(nullList.remove());
            // null
            System.out.println(nullList.poll());
            // Fruits{name='test'}
            System.out.println(fruitsList.removeFirst());
            // Fruits{name='apple'}
            System.out.println(fruitsList.remove());
            // Fruits{name='orange'}
            System.out.println(fruitsList.poll());
    
            // [Fruits{name='banana'}]
            System.out.println(fruitsList.toString());
            fruitsList.addFirst(new Fruits("apple"));
            // [Fruits{name='apple'}, Fruits{name='banana'}]
            System.out.println(fruitsList.toString());
            fruitsList.offer(new Fruits("test1"));
            fruitsList.add(new Fruits("test2"));
            fruitsList.addLast(new Fruits("test3"));
            // [Fruits{name='apple'}, Fruits{name='banana'}, Fruits{name='test1'}, Fruits{name='test2'}, Fruits{name='test3'}]
            System.out.println(fruitsList.toString());
    
            fruitsList.removeLast();
            // [Fruits{name='apple'}, Fruits{name='banana'}, Fruits{name='test1'}, Fruits{name='test2'}]
            System.out.println(fruitsList);
        }
    }
    
    

    堆栈Stack

    在这里插入图片描述

    堆栈是“后进先出”(LIFO)集合。它有时被称为叠加栈(pushdown stack),因为最后“压入”(push)栈的元素,第一个被“弹出”(pop)栈。经常用来类比栈的事物是带有弹簧支架的自助餐厅托盘。最后装入的托盘总是最先拿出来使用的。

    Java 1.0 中附带了一个 Stack 类,结果设计得很糟糕(为了向后兼容,我们永远坚持 Java 中的旧设计错误)。Java 6 添加了 ArrayDeque ,其中包含直接实现堆栈功能的方法:

    /**
     * @author myf
     */
    public class StackTest {
        public static void main(String[] args) {
            Deque<String> stringDeque = new ArrayDeque<>();
            for (String s:"My dog has fleas".split(" ")){
                stringDeque.add(s);
            }
            while (!stringDeque.isEmpty()){
                System.out.println(stringDeque.pop());
            }
        }
    }
    

    即使我们是在实现一个堆栈,但我们仍必须将其声明为 Deque 。非常容易造成混淆。
    我们可以写一个自己的Stack

    /**
     * @author myf
     */
    public class Stack<T> {
        private Deque<T> deque = new ArrayDeque<>();
        public void push(T t){
            deque.push(t);
        }
    
        public T peek(){
            return deque.peek();
        }
    
        public T pop(){
            return deque.pop();
        }
    
        public boolean isEmpty(){
            return deque.isEmpty();
        }
    
        @Override
        public String toString() {
            return deque.toString();
        }
    }
    
    

    这样我们在使用堆栈Stack时就可以使用我们自定义命名的这个堆栈了。

    这里引入了使用泛型的类定义的最简单的可能示例。类名称后面的 告诉编译器这是一个参数化类型,而其中的类型参数 T 会在使用类时被实际类型替换。基本上,这个类是在声明“我们在定义一个可以持有 T 类型对象的 Stack 。” Stack 是使用 ArrayDeque 实现的,而 ArrayDeque 也被告知它将持有 T 类型对象。注意, push() 接受类型为 T 的对象,而 peek() 和 pop() 返回类型为 T 的对象。 peek() 方法将返回栈顶元素,但并不将其从栈顶删除,而 pop() 删除并返回顶部元素。

    集合Set

    在这里插入图片描述

    Set 不保存重复的元素。 如果试图将相同对象的多个实例添加到 Set 中,那么它会阻止这种重复行为。 Set 最常见的用途是测试归属性,可以很轻松地询问某个对象是否在一个 Set 中。因此,查找通常是 Set 最重要的操作,因此通常会选择 HashSet 实现,该实现针对快速查找进行了优化。
    Set 具有与 Collection 相同的接口,因此没有任何额外的功能,不像前面两种不同类型的 List 那样。实际上, Set 就是一个 Collection ,只是行为不同。(这是继承和多态思想的典型应用:表现不同的行为。)Set 根据对象的“值”确定归属性。

    下面是使用存放 Integer 对象的 HashSet 的示例:

    /**
     * @author myf
     */
    public class SetOfInteger {
        public static void main(String[] args) {
            Random rand = new Random(47);
            Set<Integer> intset = new HashSet<>();
            for(int i = 0; i < 10000; i++){
                intset.add(rand.nextInt(30));
            }
            System.out.println(intset);
        }
    }
    /* Output:
    [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]
    */
    

    在 0 到 29 之间的 10000 个随机整数被添加到 Set 中,因此可以想象每个值都重复了很多次。但是从结果中可以看到,每一个数只有一个实例出现在结果中。

    早期 Java 版本中的 HashSet 产生的输出没有可辨别的顺序。这是因为出于对速度的追求, HashSet 使用了散列,由 HashSet 维护的顺序与 TreeSet 或 LinkedHashSet 不同,因为它们的实现具有不同的元素存储方式。 TreeSet 将元素存储在红-黑树数据结构中,而 HashSet 使用散列函数。 LinkedHashSet 因为查询速度的原因也使用了散列,但是看起来使用了链表来维护元素的插入顺序。看起来散列算法好像已经改变了,现在 Integer 按顺序排序。但是,您不应该依赖此行为:

    /**
     * @author myf
     */
    public class SetOfString {
        public static void main(String[] args) {
            Set<String> colors = new HashSet<>();
            for(int i = 0; i < 100; i++) {
                colors.add("Yellow");
                colors.add("Blue");
                colors.add("Red");
                colors.add("Red");
                colors.add("Orange");
                colors.add("Yellow");
                colors.add("Blue");
                colors.add("Purple");
            }
            System.out.println(colors);
            /* Output:
            [Red, Yellow, Blue, Purple, Orange]
            */
    
            Set<String> colors2 = new TreeSet<>();
            for(int i = 0; i < 100; i++) {
                colors2.add("Yellow");
                colors2.add("Blue");
                colors2.add("Red");
                colors2.add("Red");
                colors2.add("Orange");
                colors2.add("Yellow");
                colors2.add("Blue");
                colors2.add("Purple");
            }
            System.out.println(colors2);
            /* Output:
            [Blue, Orange, Purple, Red, Yellow]
            */
    		// true
            System.out.println(colors.contains("Yellow"));
        }
    }
    

    HashSet,String 对象似乎没有排序。要对结果进行排序,一种方法是使用 TreeSet 而不是 HashSet 。
    最常见的操作之一是使用 contains() 测试成员归属性

  • 相关阅读:
    Ubuntu vi命令
    Aria2 使用
    axel 参数 文件下载地址
    序列化模块、加密模块
    项目开发规范、time模块、日志
    递归函数(了解)
    模块
    函数进阶四(装饰器、内置函数)
    函数进阶三(生成器、生成器表达式、匿名函数)
    函数进阶二(函数名运用,闭包,迭代器)
  • 原文地址:https://www.cnblogs.com/zhangguangxiang/p/14232500.html
Copyright © 2011-2022 走看看