Java:数据结构-初始结合框架 时间复杂度和空间复杂度 初识泛型

一  初始结合框架

1.什么是Java的集合框架

Java 的集合框架(Java Collection Framework,JCF)是 Java 标准库中的一部分,用于存储和操作一组数据。它提供了一些常用的数据结构和接口,用来高效管理和操作数据。Java 的集合框架位于 java.util 包中。 

1.让我们来简单认识一下 Java 集合框架的主要组成部分和它们的用途:

1. 核心接口

Java 集合框架中定义了一些核心接口,它们是各种集合实现类的基础:

  • Collection 接口: 所有集合的根接口,提供了集合的基本操作(如添加、删除、遍历等)。
    • List 接口: 有序集合,允许重复元素。
    • Set 接口: 不允许重复元素的集合。
    • Queue 接口: 用于存储按照 FIFO(先进先出)顺序处理的元素。
    • Deque 接口: 双端队列,支持在两端添加和移除元素。
    • Map 接口: 不属于 Collection 接口体系,但常用于存储键值对映射。
2. 核心实现类

Java 集合框架中提供了接口的多种实现类,涵盖了不同的使用场景:

  • List 实现类

    • ArrayList: 基于动态数组的实现,访问速度快,适合随机访问。
    • LinkedList: 基于双向链表的实现,插入和删除速度快,适合频繁的插入/删除操作。
    • Vector: 类似于 ArrayList,但线程安全。
    • Stack: 基于 Vector 实现的栈,遵循 LIFO(后进先出)原则。
  • Set 实现类

    • HashSet: 基于哈希表的实现,元素无序且不重复,插入和查找速度快。
    • LinkedHashSet: 具有插入顺序的 HashSet 实现。
    • TreeSet: 基于红黑树的实现,元素有序(自然顺序或自定义比较器)。
  • Map 实现类

    • HashMap: 基于哈希表的键值对存储,无序。
    • LinkedHashMap: 保留键值对的插入顺序。
    • TreeMap: 基于红黑树,键值对按键有序排列。
    • Hashtable: 类似 HashMap,但线程安全。
  • Queue 和 Deque 实现类

    • PriorityQueue: 基于优先级的队列,元素按自然顺序或自定义顺序排列。
    • ArrayDeque: 基于数组的双端队列,适用于栈和队列操作。
3. 工具类

集合框架还提供了一些工具类,用于辅助操作集合:

  • Collections: 提供了各种静态方法,如排序、查找、线程安全包装等。
  • Arrays: 用于数组的操作(如转换为集合、排序、搜索等)。

 2.数据结构的概念

数据结构是计算机科学中的一个重要概念,指的是数据的存储、组织和管理方式,以便能够有效地访问和修改数据。选择适当的数据结构可以提高算法的效率,使得程序运行更快、占用更少的资源。简单来说,数据结构决定了数据如何被存储在计算机的内存中,如何被读取、操作和维护。

二 时间复杂度和空间复杂度

1.算法效率

如何判断一个算法的效率:

算法效率分析分为两种:第一种是时间效率,第二种是空间效率。时间效率被称为时间复杂度,而空间效率被称作 空间复杂度。 时间复杂度主要衡量的是一个算法的运行速度,而空间复杂度主要衡量一个算法所需要的额外空间, 在计算机发展的早期,计算机的存储容量很小。所以对空间复杂度很是在乎,但是计算机经过很长时间的发展,储存容量已经到达了一个很高的容量,所以现在对于空间复杂度已经无所谓了,不是很在乎。

2时间复杂度

时间复杂度是一个函数,定量描述了算法的运行时间,算法中基本操作的执行次数为时间复杂度。

2.1大O的渐进表示法:

结果为:

 

大O的渐进表示法的规则 :

  1. 用常数1取代运行时间中的所有加法常数。
  2. 在修改后的运行次数函数中,只保留最高阶项。
  3. 如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。

3.空间复杂度 

空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度,空间复杂度基本算的是变量的个数,和时间复杂度的算法基本一样,也用大O渐进表示法。

示例一:

 示例1使用了常数个额外空间,所以空间复杂度为 O(1)

示例二:

示例2动态开辟了N个空间,空间复杂度为 O(N) 

三 初识泛型

泛型是一种允许在类、接口和方法中定义类型参数的特性。通过泛型,实例化时可以指定具体的类型,使代码变得更加灵活。

1.包装类

1.1基本数据类型对应的包装类

基本数据类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

1.2 装箱和拆箱

装箱是将基本数据类型(如intchar)转换为对应的包装类对象(如IntegerCharacter)。

拆箱则是将包装类对象转换回基本数据类型。

1.3装箱

分为手动装修和自动装箱

手动装修
public class Test {
    public static void main(String[] args) {
        int a=10;
        Integer a1=Integer.valueOf(a);
        System.out.println(a);
    }
自动拆箱
public class Test {
    public static void main(String[] args) {

        int b=11;
        Integer c=b;
        System.out.println(c);

1.4拆箱

分为手动拆箱和自动拆箱

手动装修
public class Test {
    public static void main(String[] args) {
        Integer a=10;
        int b=a.intValue();
        System.out.println(b);
    }
自动拆箱
public class Test {
    public static void main(String[] args) {
        Integer a=10;
        int c=a;
        System.out.println(c);

大家猜一下这个代码的运行结果

public class Test {
    public static void main(String[] args) {
        Integer a=10;
        Integer b=10;
        System.out.println(a==b);

        System.out.println("----------------");
        
        Integer c=200;
        Integer d=200;
        System.out.println(c==d);
    }

 

为什么结果会不一样呢?

所以让我们一起来看一下装箱是怎么操作的

我们可以看出有一个最大值和一个最小值,所以Integer是有范围的

 

如果不在这个范围内,则不会比较数值的大小,而是比较地址。

 2.泛型

泛型就是适用于许多类型。

示例(没有用泛型方法)

class MyArray{
    public Object[] array=new Object[10];

    public void setValue(int pos,Object val){
        array[pos]=val;
    }
    public Object getValue(int pos){
        return (Object) array[pos];
    }
}
public class Test2 {


    public static void main1(String[] args) {
        MyArray myArray=new MyArray();
        myArray.setValue(1,"he");
        String s=(String) myArray.getValue(1);
        System.out.println(s);
    }

(用了泛型方法) 

class MyArray<E>{
    public Object[] array=new Object[10];

    public void setValue(int pos,E val){
        array[pos]=val;
    }
    public E getValue(int pos){
        return (E) array[pos];
    }
}
public class Test2 {
    public static void main(String[] args) {
        MyArray<String> myArray=new MyArray<>();
        myArray.setValue(1,"he");
        String a=myArray.getValue(1);
        System.out.println(a);
    }

 通过上例,我们可以看出,泛型的运用可以在实例化时具体指定类型,接收时不需要强转,非常的便利。

2.1泛型的语法

1.

class 泛型类名称<类型形参列表> {
// 这里可以使用类型参数
}
class Name<T1, T2, ..., Tn> {

}
class 泛型类名称<类型形参列表> extends 继承类 /* 这里可以使用类型参数 */ {
// 这里可以使用类型参数
}


2. class ClassName<T1, T2, ..., Tn> extends ParentClass<T1> {
// 可以只使用部分类型参数
}

class MyArray<E>extends Name<E>{
    public Object[] array=new Object[10];

    public void setValue(int pos,E val){
        array[pos]=val;
    }
    public E getValue(int pos){
        return (E) array[pos];
    }
}
public class Test2 {
    public static void main(String[] args) {
        MyArray<String> myArray=new MyArray<>();
        myArray.setValue(1,"he");
        String a=myArray.getValue(1);
        System.out.println(a);
    }

    public static void main1(String[] args) {
        MyArray myArray=new MyArray();
        myArray.setValue(1,"he");
        String s=(String) myArray.getValue(1);
        System.out.println(s);
    }

}

2.2泛型类的使用 

泛型类的语法

泛型类<类型实参> 变量名; // 定义一个泛型类引用
new 泛型类<类型实参>(构造方法实参); // 实例化一个泛型类对象

示例

        MyArray<String> myArray=new MyArray<>();

 后面的<>中写不写Integer都可以,因为编译器会自动推导出需要的类型实参为 Integer

3.泛型的上界

在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束。 

语法:

class 泛型类名称<类型形参 extends 类型边界> {
...
}

示例:

class MyArray<E extends Number>{
    public Object[] array=new Object[10];

    public void setValue(int pos,E val){
        array[pos]=val;
    }
    public E getValue(int pos){
        return (E) array[pos];
    }
}

 Number的源代码

注:只接受 Number 的子类型作为 E 的类型实参 

public class Test2 {
    public static void main(String[] args) {
        MyArray<String> myArray=new MyArray<>();
        MyArray<Integer> myArray2=new MyArray<>();
        myArray.setValue(1,"he");
        String a=myArray.getValue(1);
        System.out.println(a);
    }

 

String会报错,因为Integer 是 Number 的子类型,String 不是 Number 的子类型。

4.泛型方法

class FindMax<E extends Comparable>{
    public E findMax(E[] array){
        E max=array[0];
        for (int i = 0; i < array.length; i++) {
            if(max.compareTo(array[i])>0){
                array[i]=max;
            }
        }
        return max;
    }
}
public class TestGenergic {
    public static void main(String[] args) {
        FindMax<Integer> findMax=new FindMax<>();
        Integer[] array = {1,2,3,4,45,5,6,8};
        System.out.println(findMax.findMax(array));
    }
}

希望能对大家有所帮助!!!! 

 

 

<think>好的,我需要回答用户关于Java常用集合的初始使用方法的示例代码解析。用户提到了Collection接口,所以首先应该区分Collection的不同实现类,比如ListSet,然后分别介绍它们的常用子类,比如ArrayList、LinkedList、HashSet等。 根据用户提供的引用,引用[3]中提到了Collection的子接口ListSet,以及它们的实现类,比如ArrayList、LinkedList、HashSet等。引用[2]详细说明了HashSet的底层结构,而引用[1]展示了使用增强for循环迭代器遍历Collection集合的例子。引用[5]提到了retainAll方法的使用,可能也需要提及。 首先,我应该按照Collection的子接口来组织内容,分为ListSet两部分,每个部分介绍常用的实现类,如ArrayList、LinkedList、HashSet等。每个实现类需要说明其初始化方式、常用方法,并给出示例代码。同时,需要展示遍历方法,如增强for循环迭代器,如引用[1]中的代码所示。 对于初始化方式,Java 7之后可以使用菱形语法,比如ArrayList<String> list = new ArrayList<>();。可能需要提到不同构造方法,比如指定初始容量或从其他集合初始化。引用[4]提到了HashMap的构造方法,但用户的问题是关于Collection的,所以可能不需要涉及Map相关的内容,但需要专注于ListSet。 对于ArrayList,需要说明它基于动态数组,线程不安全,支持快速随机访问。常用方法包括add、remove、get、size等。示例代码可以展示如何添加元素、遍历元素。 对于LinkedList,它是基于链表的实现,适合频繁插入删除,同样线程不安全。可以展示如何使用addFirst、addLast等方法,以及作为队列或栈的实现。 对于Set部分,HashSet是基于哈希表,无序且不允许重复元素。初始化方式类似,需要提到哈希表的原理,如引用[2]所述。LinkedHashSet保持插入顺序,TreeSet则是有序的。可能需要简要比较这几个Set实现的不同。 在示例代码解析中,需要展示如何创建集合对象,添加元素,使用不同的遍历方式,并说明每种方式的适用场景。例如,增强for循环适用于简单遍历,而迭代器可以在遍历时删除元素。 同时,需要确保代码示例正确,比如使用指定类,避免使用原生类。例如,Collection<String> coll = new ArrayList<>();。引用[1]中的代码使用了原生类,但可以建议使用以提高类安全。 最后,生成相关问题需要考虑用户可能的后续问题,比如线程安全的集合、性能比较、如何选择集合类等。参考用户之前的引用,如引用[3]中的Vector是线程安全的,可以作为相关问题之一。 需要确保回答结构清晰,分点说明每个集合类的初始化、使用方法示例代码,并正确引用提供的参考文献。例如,在讲解HashSet时引用[2],在遍历方式时引用[1]。</think>### Java常用集合Collection初始化及使用方法解析 Java集合框架中,$Collection$ 是最基础的接口,分为$List$(有序可重复)$Set$(无序不可重复)两大子接口。以下结合示例代码解析常用实现类的初始化及核心用法。 --- #### 一、List接口实现类 ##### 1. ArrayList(动态数组) **初始化方式**: ```java // 默认初始化(容量10) List<Integer> arrayList = new ArrayList<>(); // 指定初始容量 List<String> listWithCapacity = new ArrayList<>(20); // 从其他集合初始化 List<Double> copiedList = new ArrayList<>(existingCollection); ``` **常用方法**: - `add(element)`:添加元素 - `get(index)`:通过索引访问 - `remove(index)`:按索引删除 - `size()`:获取元素数量 **示例代码**: ```java arrayList.add(5); arrayList.add(10); System.out.println(arrayList.get(0)); // 输出5 arrayList.remove(0); // 删除第一个元素 ``` ##### 2. LinkedList(双向链表) **初始化方式**: ```java LinkedList<String> linkedList = new LinkedList<>(); ``` **特有方法**: - `addFirst(element)`:头部插入 - `addLast(element)`:尾部插入 - `poll()`:获取并删除头部元素(队列操作) **示例代码**: ```java linkedList.addFirst("A"); linkedList.addLast("B"); System.out.println(linkedList.poll()); // 输出"A" ``` --- #### 二、Set接口实现类 ##### 1. HashSet(哈希表) **初始化方式**: ```java Set<Integer> hashSet = new HashSet<>(); ``` **特点**: - 基于哈希算法实现,插入/查询时间复杂度为$O(1)$[^2] - 元素无序且唯一 **示例代码**: ```java hashSet.add(3); hashSet.add(3); // 重复元素不生效 System.out.println(hashSet.size()); // 输出1 ``` ##### 2. LinkedHashSet(链表+哈希表) **初始化方式**: ```java Set<String> linkedHashSet = new LinkedHashSet<>(); ``` **特点**: - 保留元素插入顺序 - 性能略低于HashSet[^3] ##### 3. TreeSet(红黑树) **初始化方式**: ```java Set<Integer> treeSet = new TreeSet<>(); ``` **特点**: - 元素按自然顺序排序 - 插入/查询时间复杂度为$O(\log n)$ --- #### 三、集合遍历方法 1. **增强for循环**(推荐简单遍历): ```java for (Integer num : arrayList) { System.out.println(num); } ``` 2. **迭代器遍历**(支持删除操作): ```java Iterator<String> iterator = linkedList.iterator(); while (iterator.hasNext()) { String element = iterator.next(); if (element.equals("B")) { iterator.remove(); // 安全删除元素 } } ``` 引用自遍历方法示例[^1] --- #### 四、集合操作 - **交集操作**:`retainAll(Collection<?> c)`保留共有元素[^5] ```java List<Integer> list1 = new ArrayList<>(Arrays.asList(1,2,3)); List<Integer> list2 = new ArrayList<>(Arrays.asList(2,3,4)); list1.retainAll(list2); // list1变为[2,3] ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值