链表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() 测试成员归属性

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

莫逸风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值