Java_SE(六)数据结构和容器介绍

目录

一. Java中的数据结构

1.1 常见的数据结构

1.1.1 栈

1.1.2 队列

1.1.3 数组

1.1.4 链表

1.1.5 红黑树

二. Collection集合

2.1 collection概述

2.2 List接口

2.2.1 List集合概述

2.2.2 ArrayList集合

2.2.3 LinkedList集合

2.3 Set接口

2.3.1 HashSet集合

2.3.2 LinkedHashSet

三. Map查找表

3.1 常用实现类

3.2 常用方法

3.3 Map集合遍历

3.3.1 遍历所有的key

3.3.2 Entry键值对对象 

3.3.3 遍历所有的Value

3.3.4 Lambda表达式遍历

3.4 LinkedHashMap 


一. Java中的数据结构

1.1 常见的数据结构

数据存储的常用结构有:栈、队列、数组、链表和红黑树。我们分别来了解一下:

1.1.1 栈

栈(stack):又称堆栈,它是运算受限的线性表,其限制是仅允许在标的一端进行插入和删除操作,不允许在其他任何位置进行添加、查找、删除等操作。

简单的说:采用该结构的集合,对元素的存取有如下的特点:

  • 先进后出(即,存进去的元素,要在后它后面的元素依次取出后,才能取出该元素)。例如,子弹压进弹夹,先压进去的子弹在下面,后压进去的子弹在上面,当开枪时,先弹出上面的子弹,然后才能弹出下面的子弹。

  • 栈的入口、出口的都是栈的顶端位置。

这里两个名词需要注意:

  • 压栈:就是存元素。即,把元素存储到栈的顶端位置,栈中已有元素依次向栈底方向移动一个位置。

  • 弹栈:就是取元素。即,把栈的顶端位置元素取出,栈中已有元素依次向栈顶方向移动一个位置。

1.1.2 队列

队列(queue):简称队,它同堆栈一样,也是一种运算受限的线性表,其限制是仅允许在表的一端进行插入,而在表的另一端进行删除。

简单的说,采用该结构的集合,对元素的存取有如下的特点:

  • 先进先出(即,存进去的元素,要在后它前面的元素依次取出后,才能取出该元素)。例如,小火车过山洞,车头先进去,车尾后进去;车头先出来,车尾后出来。

  • 队列的入口、出口各占一侧。例如,下图中的左侧为入口,右侧为出口。

1.1.3 数组

数组(Array):是有序的元素序列,数组是在内存中开辟一段连续的空间,并在此空间存放元素。就像是一排出租屋,有100个房间,从001到100每个房间都有固定编号,通过编号就可以快速找到租房子的人。

简单的说,采用该结构的集合,对元素的存取有如下的特点:

  • 查找元素快:通过索引,可以快速访问指定位置的元素

  • 增删元素慢

    • 指定索引位置增加元素:需要创建一个新数组,将指定新元素存储在指定索引位置,再把原数组元素根据索引,复制到新数组对应索引的位置。如下图

    • 指定索引位置删除元素:需要创建一个新数组,把原数组元素根据索引,复制到新数组对应索引的位置,原数组中指定索引位置元素不复制到新数组中。如下图

1.1.4 链表

链表(linkedList):由一系列结点node(链表中每一个元素称为结点)组成,结点可以在运行时i动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。常说的链表结构有单向链表与双向链表,这里介绍的是单向链表

简单的说,采用该结构的集合,对元素的存取有如下的特点:

  • 多个结点之间,通过地址进行连接。例如,多个人手拉手,每个人使用自己的右手拉住下个人的左手,依次类推,这样多个人就连在一起了。

  • 查找元素慢:想查找某个元素,需要通过连接的节点,依次向后查找指定元素

  • 增删元素快:

    • 增加元素:只需要修改连接下个元素的地址即可。

    • 删除元素:只需要修改连接下个元素的地址即可。

1.1.5 红黑树

二叉树binary tree):是每个结点不超过2的有序树(tree)

简单的理解,就是一种类似于我们生活中树的结构,只不过每个结点上都最多只能有两个子结点。二叉树是每个节点最多有两个子树的树结构。顶上的叫根结点,两边被称作“左子树”和“右子树”。

如图:

我们要说的是二叉树的一种比较有意思的叫做红黑树,红黑树本身就是一颗二叉查找树,将节点插入后,该树仍然是一颗二叉查找树。也就意味着,树的键值仍然是有序的。

红黑树的约束:

  1. 节点可以是红色的或者黑色的
  2. 根节点是黑色的
  3. 叶子节点(特指空节点)是黑色的
  4. 每个红色节点的子节点都是黑色的
  5. 任何一个节点到其每一个叶子节点的所有路径上黑色节点数相同

红黑树的特点:

        速度特别快,趋近平衡树,查找叶子元素最少和最多次数不多于二倍

二. Collection集合

2.1 collection概述

Collection:单列集合类的根接口,用于存储一系列符合某种规则的元素,有两个重要的子接口,分别是 java.util.Listjava.util.Set

Collection是所有单列集合的父接口,因此在Collection中定义了单列集合(List和Set)通用的一些方法,这些方法可用于操作所有的单列集合。方法如下:

  • public boolean add(E e) :  把给定的对象添加到当前集合中 。
  • public void clear() :清空集合中所有的元素。
  • public boolean remove(E e) : 把给定的对象在当前集合中删除。
  • public boolean contains(E e) : 判断当前集合中是否包含给定的对象。
  • public boolean isEmpty() : 判断当前集合是否为空。
  • public int size() : 返回集合中元素的个数。
  • public Object[] toArray() : 把集合中的元素,存储到数组中。

2.2 List接口

2.2.1 List集合概述

java.util.List 接口继承自 Collection 接口,是单列集合的一个重要分支,习惯性地会将实现了List接口的对象称为List集合。在List集合中允许出现重复的元素,所有的元素是以一种线性方式进行存储的,在程序中可以通过索引来访问集合中的指定元素。另外,List集合还有一个特点就是元素有序,即元素的存入顺序和取出顺序一致。

List接口特点:

  • 1. 它是一个元素存取有序的集合。
  • 2. 它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素。
  • 3. 集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。

List作为Collection集合的子接口,不但继承了Collection接口中的全部方法,而且还增加了一些根据元素索引来操作集合的特有方法,如下:

  • public void add(int index, E element) : 将指定的元素,添加到该集合中的指定位置上。
  • public E get(int index) :返回集合中指定位置的元素。
  • public E remove(int index) : 移除列表中指定位置的元素, 返回的是被移除的元素。
  • public E set(int index, E element) :用指定元素替换集合中指定位置的元素,返回值的更新前的元素。

2.2.2 ArrayList集合

java.util.ArrayList 集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以 ArrayList 是最常用的集合。

常用的方法有:

  • public boolean add(E e) :将指定的元素添加到此集合的尾部。
  • public E remove(int index) :移除此集合中指定位置上的元素。返回被删除的元素。
  • public E get(int index) :返回此集合中指定位置上的元素。返回获取的元素。
  • public int size() :返回此集合中的元素数。遍历集合时,可以控制索引范围,防止越界。

2.2.3 LinkedList集合

java.util.LinkedList:集合数据存储的结构是链表结构。方便元素添加、删除的集合。LinkedList是一个双向链表,图示如下:

 常用的方法有:

  • public void addFirst(E e) :将指定元素插入此列表的开头。
  • public void addLast(E e) :将指定元素添加到此列表的结尾。
  • public E getFirst() :返回此列表的第一个元素。
  • public E getLast() :返回此列表的最后一个元素。
  • public E removeFirst() :移除并返回此列表的第一个元素。
  • public E removeLast() :移除并返回此列表的最后一个元素。
  • public E pop() :从此列表所表示的堆栈处弹出一个元素。
  • public void push(E e) :将元素推入此列表所表示的堆栈。
  • public boolean isEmpty() :如果列表不包含元素,则返回true。

2.3 Set接口

java.util.Set:同样继承自 Collection 接口,与 Collection 接口中的方法基本一致。Set 接口中元素无序,并且都会以某种规则保证存入的元素不出现重复。

2.3.1 HashSet集合

1. java.util.HashSet :是 Set 接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序不一致)。底层的实现其实是一个`java.util.HashMap`支持。HashSet是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。保证元素唯一性的方式依赖于:hashCode与equals方法。

2. 关于哈希表:

JDK1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。

简单的来说,哈希表是由数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的,如下图所示。

 哈希存储流程图:

总而言之,JDK1.8引入红黑树大程度优化了HashMap的性能,那么对于我们来讲保证HashSet集合元素的唯一,其实就是根据对象的hashCode和equals方法来决定的。如果我们往集合中存放自定义的对象,那么保证其唯一,就必须复写hashCode和equals方法建立属于当前对象的比较方式。

2.3.2 LinkedHashSet

在HashSet下面有一个子类java.util.LinkedHashSet,它是链表和哈希表组合的一个数据存储结构,能够保证元素有序。演示如下:

public class LinkedHashSetDemo {
	public static void main(String[] args) {
		Set<String> set = new LinkedHashSet<String>();
		set.add("bbb");
		set.add("aaa");
		set.add("abc");
		set.add("bbc");
        Iterator<String> it = set.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}
	}
}
结果:
  bbb
  aaa
  abc
  bbc

三. Map查找表

Map体现的结构是一个多行两列的表格,其中左列称为key,右列称为value。

  • Map总是成对保存数据,并且总是根据key获取对应的value,因此我们可以将查询的条件作为key查询对应的结果作为value保存到Map中。
  • Map有一个要求:key不允许重复(equals比较的结果)

3.1 常用实现类

  • HashMap<K,V>:存储数据采用的哈希表结构,元素的存取顺序不能保证一致。由于要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。

  • LinkedHashMap<K,V>:HashMap下有个子类LinkedHashMap,存储数据采用的哈希表结构+链表结构。通过链表结构可以保证元素的存取顺序一致;通过哈希表结构可以保证的键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。

3.2 常用方法

  • public V put(K key, V value) :  把指定的键与指定的值添加到Map集合中。
  • public V remove(Object key) : 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。
  • public V get(Object key) :根据指定的键,在Map集合中获取对应的值。
  • boolean containsKey(Object key) :判断集合中是否包含指定的键。
  • public Set<K> keySet() : 获取Map集合中所有的键,存储到Set集合中。
  • public Set<Map.Entry<K,V>> entrySet() : 获取到Map集合中所有的键值对对象的集合(Set集合)。
public class MapDemo {
    public static void main(String[] args) {
        //创建 map对象
        HashMap<String, String>  map = new HashMap<String, String>();

        //添加元素到集合
        map.put("西游记", "孙悟空");
        map.put("红楼梦", "贾宝玉");
        map.put("三国演义", "曹孟德");
        System.out.println(map);

        //String remove(String key)
        System.out.println(map.remove("西游记"));
        System.out.println(map);

        // 想要查看 红楼梦里有谁
        System.out.println(map.get("红楼梦"));   
    }
}

注意:

  • 使用put方法时,若指定的键(key)在集合中没有,则没有这个键对应的值,返回null,并把指定的键值添加到集合中; 
  • 若指定的键(key)在集合中存在,则返回值为集合中键对应的值(该值为替换前的值),并把指定键所对应的值,替换成指定的新值。 

3.3 Map集合遍历

3.3.1 遍历所有的key

键找值方式:即通过元素中的键,获取键所对应的值。

分析步骤:

  • 1. 获取Map中所有的键,由于键是唯一的,所以返回一个Set集合存储所有的键。方法提示:keyset()
  • 2. 遍历键的Set集合,得到每一个键。
  • 3. 根据键,获取键所对应的值。方法提示:get(K key)
public class MapDemo01 {
    public static void main(String[] args) {
        //创建Map集合对象 
        HashMap<String, String> map = new HashMap<String, String>();
        //添加元素到集合 
        map.put("郭德纲", "于谦");
        map.put("孟鹤堂", "周九良");
        map.put("郭麒麟","闫壮壮");

        //获取所有的键  获取键集
        Set<String> keys = map.keySet();
        // 遍历键集 得到 每一个键
        for (String key : keys) {
          	//key  就是键
            //获取对应值
            String value = map.get(key);
            System.out.println(key + "的CP是:" + value);
        }  
    }
}

3.3.2 Entry键值对对象 

键值对方式:即通过集合中每个键值对(Entry)对象,获取键值对(Entry)对象中的键与值。

操作步骤:

  • 获取Map集合中,所有的键值对(Entry)对象,以Set集合形式返回。方法提示:entrySet()。
  • 遍历包含键值对(Entry)对象的Set集合,得到每一个键值对(Entry)对象。
  • 通过键值对(Entry)对象,获取Entry对象中的键与值。  方法提示:getkey() getValue()。
    public class MapDemo02 {
        public static void main(String[] args) {
            // 创建Map集合对象 
            HashMap<String, String> map = new HashMap<String, String>();
            // 添加元素到集合 
            map.put("郭德纲", "于谦");
            map.put("孟鹤堂", "周九良");
            map.put("郭麒麟","闫壮壮");
    
            // 获取 所有的 entry对象  entrySet
            Set<Entry<String, String>> entrySet = map.entrySet();
    
            // 遍历得到每一个entry对象
            for (Entry<String, String> entry : entrySet) {
               	// 解析 
                String key = entry.getKey();
                String value = entry.getValue();  
                System.out.println(key + "的CP是:" + value);
            }
        }
    }

3.3.3 遍历所有的Value

  此处用到Collection values(),该方法会将当前Map中所有的value以一个集合形式返回。

public class MapDemo02 {
    public static void main(String[] args) {
        // 创建Map集合对象 
        HashMap<String, String> map = new HashMap<String, String>();
        // 添加元素到集合 
        map.put("郭德纲", "于谦");
        map.put("孟鹤堂", "周九良");
        map.put("郭麒麟", "闫壮壮");
        
        Collection<String> values = map.values();
            for(String value : values){
                System.out.println("value:" + value);
            }
    }
}

3.3.4 Lambda表达式遍历

JDK8之后集合框架支持了使用lambda表达式遍历。因此Map和Collection都提供了foreach方法,通过lambda表达式遍历元素。 

public class MapDemo02 {
    public static void main(String[] args) {
        // 创建Map集合对象
        HashMap<String, String> map = new HashMap<String, String>();
        // 添加元素到集合
        map.put("郭德纲", "于谦");
        map.put("孟鹤堂", "周九良");
        map.put("郭麒麟", "闫壮壮");

        map.forEach(
                (k, v) -> System.out.println(k + ":" + v)
        );

    }
}

3.4 LinkedHashMap 

LinkedHashMap,它是链表和哈希表组合的一个数据存储结构。来保证元素有序,速度快。

public class LinkedHashMapDemo {
    public static void main(String[] args) {
        LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
        map.put("西游记", "猪八戒");
        map.put("红楼梦", "林黛玉");
        map.put("水浒传", "武大郎");
        Set<Entry<String, String>> entrySet = map.entrySet();
        for (Entry<String, String> entry : entrySet) {
            System.out.println(entry.getKey() + "  " + entry.getValue());
        }
    }
}

执行结果:
西游记  猪八戒
红楼梦  林黛玉
水浒传  武大郎

最后,附一张图供各位参考


本文完!

写在结尾:

一个java菜鸟,发布于北京海淀。

好记性不如烂笔头,持续学习,坚持输出~今天是持续写作的第11天。可以点赞、评论、收藏啦。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

码云说

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

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

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

打赏作者

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

抵扣说明:

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

余额充值