Java集合和数据结构

1. 集合

普通的对象数组的最大问题在于数组中的元素个数是固定的,不能动态的扩充大小,所以最 早的时候可以通过链表实现一个动态对象数组。但是这样做毕竟太复杂了,所以在 Java 中为了方便用户操作各个数据结构, 所以引入了类集的概念,有时候就可以把类集称为 java 对数据结构的实现。

在整个类集中的,这个概念是从 JDK1.2(Java 2)之后才正式引入的,最早也提供了很多的操作类,但是并没有完 整的提出类集的完整概念。 类集中最大的几个操作接口:Collection、Map、Iterator,这三个接口为以后要使用的最重点的接口。
所有的类集操作的接口或类都在 java.util 包中。

在这里插入图片描述

1.1 Collection接口

Collection 接口是在整个 Java 类集中保存单值的最大操作父接口,里面每次操作的时候都只能保存一个对象的数据。 此接口定义在 java.util 包中。
此接口定义如下:

public interface Collection<E> extends Iterable<E>

此接口的常用方法如下所示:
在这里插入图片描述
但是,在开发中不会直接使用 Collection 接口。而使用其操作的子接口:List、Set。

1.2 List 接口

在整个集合中 List 是 Collection 的子接口,里面的所有内容都是允许重复的。

List 子接口的定义:

public interface List<E> extends Collection<E> 

此接口上依然使用了泛型技术。此接口对于 Collection 接口来讲有如下的扩充方法:
在这里插入图片描述
了解了 List 接口之后,那么该如何使用该接口呢?需要找到此接口的实现类,常用的实现类有如下几个: · ArrayList(95%)、Vector(4%)、LinkedList(1%)

1.3 ArrayList

ArrayList 是 List 接口的子类,此类的定义如下:
publicclassArrayListextendsAbstractList implementsList,RandomAccess,Cloneable,Serializable
此类继承了 AbstractList 类。AbstractList 是 List 接口的子类。AbstractList 是个抽象类,适配器设计模式。
例子ArrayList增加和取得元素

package org.listdemo.arraylistdemo; 
import java.util.ArrayList; 
import java.util.List; 
public class ArrayListDemo01 { 
	public static void main(String[] args) {
		List<String> all = new ArrayList<String>(); // 实例化List对象,并指定泛型类型 
		all.add("hello "); // 增加内容,此方法从Collection接口继承而来 
		all.add(0, "LAMP ");// 增加内容,此方法是List接口单独定义的 
		all.add("world"); // 增加内容,此方法从Collection接口继承而来 
		System.out.println(all); // 打印all对象调用toString()方法 
		}
}

以上的操作向集合中增加了三个元素,其中在指定位置增加的操作是 List 接口单独定义的。随后进行输出的时候, 实际上调用的是 toString()方法完成输出的。 可以发现,此时的对象数组并没有长度的限制,长度可以任意长,只要是内存够大就行。
例:删除元素,并且使用循环的方式输出。

package org.listdemo.arraylistdemo; 
import java.util.ArrayList; 
import java.util.List;
public class ArrayListDemo02 { 
	public static void main(String[] args) {
		List<String> all = new ArrayList<String>(); // 实例化List对象,并指定泛型类型 
		all.add("hello "); // 增加内容,此方法从Collection接口继承而来 
		all.add(0, "LAMP ");// 增加内容,此方法是List接口单独定义的 
		all.add("world"); // 增加内容,此方法从Collection接口继承而来 
		all.remove(1); // 根据索引删除内容,此方法是List接口单独定义的 
		all.remove("world");// 删除指定的对象 
		System.out.print("集合中的内容是:"); 
		for (int x = 0; x < all.size(); x++) { // size()方法从Collection接口继承而来 
			System.out.print(all.get(x) + "、"); // 此方法是List接口单独定义的 
		}
	}
}

1.4 Vector

Vector类实现了可增长的对象数组。 像数组一样,它包含可以使用整数索引访问的组件。 但是, Vector的大小可以根据需要增大或缩小,以便在创建Vector后添加和删除元素。

从Java 2平台v1.2开始,该类被改进以实现List接口,使其成为Java Collections Framework的成员。 与新的集合实现不同, Vector是同步的。 如果不需要线程安全实现,建议使用ArrayList代替Vector 。

与 ArrayList 一样,Vector 本身也属于 List 接口的子类,此类的定义如下:
public class Vector extends AbstractList implementsList,RandomAccess,Cloneable,Serializable
此类与 ArrayList 类一样,都是 AbstractList 的子类。所以,此时的操作只要是 List 接口的子类就都按照 List 进行操作。

package org.listdemo.vectordemo; 
import java.util.List; 
import java.util.Vector; 
public class VectorDemo01 { 
	public static void main(String[] args) {
		List<String> all = new Vector<String>(); // 实例化List对象,并指定泛型类型 
		all.add("hello "); // 增加内容,此方法从Collection接口继承而来 
		all.add(0, "LAMP ");// 增加内容,此方法是List接口单独定义的 
		all.add("world"); // 增加内容,此方法从Collection接口继承而来 
		all.remove(1); // 根据索引删除内容,此方法是List接口单独定义的 
		all.remove("world");// 删除指定的对象 
		System.out.print("集合中的内容是:"); 
		for (int x = 0; x < all.size(); x++) { // size()方法从Collection接口继承而来 
			System.out.print(all.get(x) + "、"); // 此方法是List接口单独定义的 
		} 
	} 
} 

以上的操作结果与使用 ArrayList 本身并没有任何的区别。因为操作的时候是以接口为操作的标准。

2 见数据结构

数据存储的常用结构有:栈(stack)、队列(queue)、数组(Array)、链表(LinkedList)和红黑树。

2.1 stack

栈:stack,又称堆栈, 栈(stack)是限定仅在表尾进行插入和删除操作的线性表。我们把允许插 入和删除的一端称为栈顶,另一端称为栈底,不含任何数据元素的栈称为空栈。栈又称为先进后出 的线性表

特点:

  1. 先进后出(即,存进去的元素,要在后它后面的元素依次取出后,才能取出该元素)。例如,子弹 压进弹夹,先压进去的子弹在下面,后压进去的子弹在上面,当开枪时,先弹出上面的子弹,然后 才能弹出下面的子弹。
  2. 栈的入口、出口的都是栈的顶端位置。
    例:
    在这里插入图片描述

2.2 队列 queue

队列:queue,简称队, 队列是一种特殊的线性表,是运算受到限制的一种线性表,只允许在表的 一端进行插入,而在另一端进行删除元素的线性表。队尾(rear)是允许插入的一端。队头(front)是 允许删除的一端。空队列是不含元素的空表。

特点:

  1. 先进先出(即,存进去的元素,要在后它前面的元素依次取出后,才能取出该元素)。例如,小火 车过山洞,车头先进去,车尾后进去;车头先出来,车尾后出来。
  2. 队列的入口、出口各占一侧。例如,下图中的左侧为入口,右侧为出口。
    在这里插入图片描述

2.3 数组 Array

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

特点:

  1. 查找元素快:通过索引,可以快速访问指定位置的元素
  2. 增删元素慢
    指定索引位置增加元素:需要创建一个新数组,将指定新元素存储在指定索引位置,再把原 数组元素根据索引,复制到新数组对应索引的位置。
    指定索引位置删除元素:需要创建一个新数组,把原数组元素根据索引,复制到新数组对应 索引的位置,原数组中指定索引位置元素不复制到新数组中。如下图

2.4 链表 LinkedList

链表:linked list,由一系列结点node(链表中每一个元素称为结点)组成,结点可以在运行时i动 态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的 指针域。我们常说的链表结构有单向链表与双向链表,那么这里给大家介绍的是单向链表。
在这里插入图片描述
特点:

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

在这里插入图片描述
2. 查找元素慢:想查找某个元素,需要通过连接的节点,依次向后查找指定元素
3. 增删元素快:
增加元素:只需要修改连接下个元素的地址即可。
在这里插入图片描述
删除元素:只需要修改连接下个元素的地址即可。
在这里插入图片描述

2.5 红黑树

二叉树:binary tree ,是每个结点不超过2的有序树(tree) 。
简单的理解,就是一种类似于我们生活中树的结构,只不过每个结点上都多只能有两个子结点。
二叉树是每个节点多有两个子树的树结构。顶上的叫根结点,两边被称作“左子树”和“右子树”。
如图:
在这里插入图片描述
红黑树:红黑树本身就是一颗二叉查找树,将节点插入 后,该树仍然是一颗二叉查找树。也就意味着,树的键值仍然是有序的。

红黑树的约束:

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

3. 链表和二叉树

3.1 链表

链表 [Linked List]:链表是由一组(内存)不必相连(不必相连:可以连续也可以不连续)的内存结构(节点),按特定的顺序链接在一起的抽象数据类型。

数组和链表的区别和优缺点:
数组是一种连续存储线性结构,元素类型相同,大小相等
数组的优点: 存取速度快
数组的缺点: 事先必须知道数组的长度 插入删除元素很慢 空间通常是有限制的 需要大块连续的内存块 插入删除元素的效率很低

链表是离散存储线性结构 n 个节点离散分配,彼此通过指针相连,每个节点只有一个前驱节点,每个节点只有一 个后续节点,首节点没有前驱节点,尾节点没有后续节点。

链表优点: 空间没有限制 插入删除元素很快
链表缺点: 存取速度很慢

链表节点:

class Node {
	Object data;
	Node next;
}

3.2 链表的结构

链表常用的有 3 类: 单链表、双向链表、循环链表。
在这里插入图片描述
链表的核心操作集有 3 种:插入、删除、查找(遍历)

3.2.1 单链表

单链表 [Linked List]:由各个内存结构通过一个 Next 指针链接在一起组成,每一个内 存结构都存在后继内存结构(链尾除外),内存结构由数据域和 Next 指针域组成。
在这里插入图片描述
解析:
Data 数据 + Next 指针,组成一个单链表的内存结构 ;
第一个内存结构称为 链头,最后一个内存结构称为 链尾;
链尾的 Next 指针设置为 NULL [指向空];
单链表的遍历方向单一(只能从链头一直遍历到链尾)

单链表操作集:
在这里插入图片描述

3.2.2 双向链表

双向链表 [Double Linked List]:由各个内存结构通过指针 Next 和指针 Prev 链接在一 起组成,每一个内存结构都存在前驱内存结构和后继内存结构(链头没有前驱,链尾没有后 继),内存结构由数据域、Prev 指针域和 Next 指针域组成。

双向链表实现图示:
在这里插入图片描述
解析:
Data 数据 + Next 指针 + Prev 指针,组成一个双向链表的内存结构;
第一个内存结构称为 链头,最后一个内存结构称为 链尾;
链头的 Prev 指针设置为 NULL, 链尾的 Next 指针设置为 NULL;
Prev 指向的内存结构称为 前驱, Next 指向的内存结构称为 后继;
双向链表的遍历是双向的,即如果把从链头的 Next 一直到链尾的[NULL] 遍历方向定 义为正向,那么从链尾的 Prev 一直到链头 [NULL ]遍历方向就是反向;

双向链表操作集:
在这里插入图片描述
在这里插入图片描述

3.2.3 循环链表

单向循环链表 [Circular Linked List] : 由各个内存结构通过一个指针 Next 链接在一起 组成,每一个内存结构都存在后继内存结构,内存结构由数据域和 Next 指针域组成。

双向循环链表 [Double Circular Linked List] : 由各个内存结构通过指针 Next 和指针 Prev 链接在一起组成,每一个内存结构都存在前驱内存结构和后继内存结构,内存结构由 数据域、Prev 指针域和 Next 指针域组成。

在这里插入图片描述
解析:

循环链表分为单向、双向两种;
单向的实现就是在单链表的基础上,把链尾的 Next 指针直接指向链头,形成一个闭环;
双向的实现就是在双向链表的基础上,把链尾的 Next 指针指向链头,再把链头的 Prev 指针指向链尾,形成一个闭环;
循环链表没有链头和链尾的说法,因为是闭环的,所以每一个内存结构都可以充当链头和链尾;

循环链表操作集:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.3 二叉树

二叉树是树的一种,每个节点最多可具有两个子树,即结点的度最大为 2(结点度:结点拥 有的子树数)。
在这里插入图片描述
在这里插入图片描述

定义:当前根节点的左边全部比根节点小,当前根节点的右边全部比根节点大。
一棵树至少会有一个节点(根节点) 树由节点组成,每个节点的数据结构是这样的:
在这里插入图片描述
因此,我们定义树的时候往往是->定义节点->节点连接起来就成了树,而节点的定义就 是:一个数据、两个指针(如果有节点就指向节点、没有节点就指向 null)

二叉树节点:

class Node {
	Object data;
	Node left;
	Node right;
}

3.3.1 二叉树种类

  1. 斜树
    所有结点都只有左子树,或者右子树。
    在这里插入图片描述

  2. 满二叉树
    所有的分支节点都具有左右节点。
    在这里插入图片描述

  3. 完全二叉树
    若设二叉树的深度为 h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。

在这里插入图片描述

3.3.2 二叉树的性质

二叉树第 i 层上的结点数目最多为 2^(i-1) (i≥1)
深度为 h 的二叉树至多有 2^h-1 个结点(h≥1)
包含 n 个结点的二叉树的高度至少为 log2 (n+1)
在任意一棵二叉树中,若终端结点的个数为 n0,度为 2 的结点数为 n2,则 n0=n2+1

3.3.3 二叉树的遍历方式

1. 先序遍历
先访问根节点,然后访问左节点,最后访问右节点(根->左->右)
2. 中序遍历
先访问左节点,然后访问根节点,最后访问右节点(左->根->右)
3. 后序遍历
先访问左节点,然后访问右节点,最后访问根节点(左->右->根)
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值