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

链表LinkedList、堆栈Stack、集合Set的更多相关文章

  1. 《Java数据结构与算法》笔记-CH5-链表-4用链表实现堆栈

    //用链表实现堆栈 /** * 节点类 */ class LinkS { private long data; public LinkS next; public LinkS(long d) { th ...

  2. C# 队列(Queue) 和堆栈(Stack)

    队列 (Queue)                                                                                          ...

  3. 用LinkedList模拟Stack功能

    集合体系在Java中比较重要,整个集合体系是在JDK1.2版本后出现,Collection作为整个体系的顶层,拥有整个体系通用的功能.对于其下面的小弟,也是各有千秋.下面就一道面试题来看看Linked ...

  4. java中堆栈(stack)和堆(heap)(还在问静态变量放哪里,局部变量放哪里,静态区在哪里.....进来)

    (1)内存分配的策略 按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈式的,和堆式的. 静态存储分配是指在编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在编 译时就可以给 ...

  5. java中堆栈(stack)和堆(heap)

    原文地址:http://blog.csdn.net/jerryao/article/details/874101 1.内存分配策略 按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈 ...

  6. 集合、ArrayList 集合。Stack集合。Queue集合。以及Hashtable集合

    arrayList 首先复制Colections加  : 创建arrayList ar =new arrayList(); //ArrayList al=new ArrayList();        ...

  7. 3.2 java中堆栈(stack)和堆(heap)(还在问静态变量放哪里,局部变量放哪里,静态区在哪里.....进来)

    (1)内存分配的策略 按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈式的,和堆式的. 静态存储分配是指在编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在编 译时就可以给 ...

  8. Stack集合 Queue队列集合 Hashtable哈希表

    Stack集合 干草堆集合 栈集合 栈;stack,先进后出,一个一个赋值,一个一个取值,安装顺序来. 属性和方法 实例化 初始化 Stack st = new Stack(); 添加元素 个数 Co ...

  9. Stack集合、queue集合、hashtable集合

    1.栈:Stack,先进后出,一个一个赋值,一个一个取值,按顺序. .count           取集合内元素的个数 .push()         将元素一个一个推入集合中//stack集合存入 ...

随机推荐

  1. Requests方法 -- post

    >>> import requests  导入requests库 >>> help(requests)  #查看requests方法Help on package ...

  2. Delimiter must not be alphanumeric or backslash php报错原因

    昨天写了一个小程序,其中用到了正则表达式去匹配内容.  php源代码如下: preg_match("\b(\w+)\b\s+\1\b",$match):   此报错警告的中文意思是 ...

  3. Java集合 - 初始化写法

    List的初始化方法 方法一 List<Integer> list= new ArrayList<Integer>(){{ add(1); add(2); add(3); }} ...

  4. Python基础之创建文件夹与删除文件夹。

    参考链接:https://blog.csdn.net/weixin_43826242/article/details/87101436 创建目录结构 # 创建文件目录结构 def create_fol ...

  5. CreateWindow() -- 创建普通的窗口

    (1)函数原型 1 HWND CreateWindow( 2 LPCTSTR lpClassName, //pointer to register class name 3 LPCTSTR lpWin ...

  6. .net 5+ 知新:【2】 .Net Framework 、.Net 、 .NET Standard的概念与区别

    作为了解历史和眼睛或者过程,我们需要将 .Net Framwork ..Net. .Net Stander几个概念进行下理解. .net 代表跨平台框架,从.net 5开始就统一叫.net,废弃原来的 ...

  7. ondblclick="return showCodeList 分析思路

    <Div id="divApproveRejectReasonInput" style="display:none"><input class ...

  8. java标识符,关键字,注释及生成Doc文档

    # java语法基础 ## 标识符,关键字与注释 ### 标识符 1.类名,变量名,方法名都称为标识符. 2.命名规则:(1):所有的标识符都应该以字母(AZ,或者az)美元符($)或者下划线(_)开 ...

  9. 快速上手 Rook,入门云原生存储编排

    Rook 是一个开源 cloud-native storage orchestrator(云原生存储编排器),为各种存储解决方案提供平台.框架和支持,以与云原生环境进行原生集成. Rook 将存储软件 ...

  10. Server-Speaks-First 有点坑,Linkerd 2.10 中的协议检测和不透明端口

    协议检测(Protocol detection),顾名思义,允许 Linkerd 自动检测 TCP 连接中使用的协议. Linkerd 的设计原则之一是"just work",协议 ...