Java基础十七:数据结构

数据结构

数据结构 = 存放数据的容器 + 数据的排列,存取规则

java日常开发只用两大类:

  • 数组
  • 集合(List、Set、Map)

1. 数组 Array

特点:长度固定,一旦定义不能更改;只能存储同一种数据类型(基本类型/引用类型),在内存中占用连续的存储空间;通过索引快速访问元素;属于引用类型

java 复制代码
//数据一旦初始化,长度就已经定死了,无法更改
public class ArrayDemo {
    public static void main(String[] args) {
        // 声明并创建长度为 3 的 int 数组
        int[] arr = new int[3]; 
        
        // 可以赋值
        arr[0] = 10;
        arr[1] = 20;
        arr[2] = 30;
        
        // 报错!数组越界,因为长度固定为3,不能访问索引3
        // arr[3] = 40; 
        
        System.out.println("数组长度:" + arr.length); // 输出:3
    }
}

//数组是类型安全的容器,只能存好定义好的类型
public class ArrayType {
    public static void main(String[] args) {
        // int 数组,只能存整数
        int[] nums = {1,2,3}; 
        // nums[0] = "Java"; 报错!不能存字符串
        
        // String 数组,只能存字符串
        String[] names = new String[2];
        names[0] = "张三";
        // names[1] = 100; 报错!
    }
}

//通过数组名【索引】快速读写,效率极高
public class ArrayIndex {
    public static void main(String[] args) {
        // 静态初始化
        String[] fruits = {"苹果", "香蕉", "橙子"}; 
        
        // 访问:索引 0 是第一个元素
        System.out.println(fruits[0]); // 苹果
        System.out.println(fruits[2]); // 橙子
        
        // 修改元素
        fruits[1] = "葡萄";
        System.out.println(fruits[1]); // 葡萄
    }
}

//创建数组时,未手动赋值的元素会自动赋默认值
int → 0
double → 0.0
boolean → false
引用类型(String / 对象)→ null
public class ArrayDefault {
    public static void main(String[] args) {
        // 只指定长度,不赋值
        int[] arr = new int[3]; 
        
        System.out.println(arr[0]); // 0
        System.out.println(arr[1]); // 0
        
        boolean[] boolArr = new boolean[2];
        System.out.println(boolArr[0]); // false
        
        String[] strArr = new String[2];
        System.out.println(strArr[0]); // null
    }
}

//数组变量是引用,指向堆内存中的数组对象
public class ArrayRef {
    public static void main(String[] args) {
        // arr1 是引用,指向堆内存的数组对象
        int[] arr1 = {10,20}; 
        
        // 把引用赋值给 arr2,两个引用指向同一个数组
        int[] arr2 = arr1; 
        
        arr2[0] = 100; // 修改 arr2,arr1 也会变
        
        System.out.println(arr1[0]); // 100
    }
}

//因为长度固定,用for/增强for遍历最方便:
public class ArrayLoop {
    public static void main(String[] args) {
        int[] arr = {1,2,3,4,5};
        
        // 普通 for 循环(通过索引)
        for(int i=0; i<arr.length; i++){
            System.out.print(arr[i] + " ");
        }
        
        System.out.println();
        
        // 增强 for 循环(直接取元素)
        for(int num : arr){
            System.out.print(num + " ");
        }
    }
}

缺点 :长度固定,不够用只能新建数组复制,很麻烦 → 所以有 ArrayList

2. List 列表(有序、可重复)

List 核心特点
  1. 有序:存入顺序和取出顺序一致
  2. 可重复:允许存放重复元素
  3. 有索引 :可以通过下标 0,1,2... 操作元素
  4. 长度可变:动态扩容,不用像数组一样固定长度
  5. 支持泛型:可以限制存放指定类型,避免类型转换异常
  6. 常用实现类
    • ArrayList查询快、增删慢,日常最常用
    • LinkedList增删快、查询慢,适合频繁插入删除
    • Vector:线程安全,效率低,基本不用
常用List实现类区别
底层结构 查询 增删 线程安全
ArrayList 动态数组 不安全
LinkedList 双向链表 不安全
Vector 动态数组 一般 安全

开发 90% 场景直接用 ArrayList

基础使用代码举例:

java 复制代码
//1. 创建 List、添加元素
import java.util.ArrayList;
import java.util.List;

public class ListDemo1 {
    public static void main(String[] args) {
        // 泛型<String>:只能存字符串
        List<String> list = new ArrayList<>();

        // 添加元素
        list.add("张三");
        list.add("李四");
        list.add("王五");
        list.add("张三"); // List允许重复

        System.out.println(list); // [张三, 李四, 王五, 张三]
    }
}

//2. 常用增删改查方法
import java.util.ArrayList;
import java.util.List;

public class ListDemo2 {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();

        // 1. 添加
        list.add(10);
        list.add(20);
        list.add(30);
        System.out.println("添加后:" + list);

        // 2. 根据索引插入
        list.add(1, 99);
        System.out.println("索引1插入99:" + list);

        // 3. 根据索引获取元素
        Integer num = list.get(2);
        System.out.println("索引2元素:" + num);

        // 4. 修改元素
        list.set(2, 88);
        System.out.println("修改索引2:" + list);

        // 5. 根据索引删除
        list.remove(1);
        System.out.println("删除索引1:" + list);

        // 6. 根据元素删除
        list.remove(Integer.valueOf(30));
        System.out.println("删除元素30:" + list);

        // 7. 获取集合大小
        System.out.println("元素个数:" + list.size());

        // 8. 判断是否包含元素
        System.out.println("是否包含10:" + list.contains(10));

        // 9. 清空集合
        // list.clear();
    }
}

//list四种遍历方式(比掌握)
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ListForEach {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Java");
        list.add("Python");
        list.add("C++");

        // 方式1:普通for循环(带索引)
        System.out.println("===== 普通for =====");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }

        // 方式2:增强for循环(最常用)
        System.out.println("===== 增强for =====");
        for (String s : list) {
            System.out.println(s);
        }

        // 方式3:迭代器 Iterator
        System.out.println("===== 迭代器 =====");
        Iterator<String> it = list.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }

        // 方式4:Lambda 表达式(JDK8+)
        System.out.println("===== Lambda =====");
        list.forEach(System.out::println);
    }
}

//LinkedList 特有用法
import java.util.LinkedList;

public class LinkedListDemo {
    public static void main(String[] args) {
        LinkedList<String> link = new LinkedList<>();

        // 首尾添加
        link.addFirst("第一个");
        link.addLast("最后一个");
        link.add("中间");

        System.out.println(link);

        // 获取首尾元素
        System.out.println("首元素:" + link.getFirst());
        System.out.println("尾元素:" + link.getLast());

        // 删除首尾
        link.removeFirst();
        link.removeLast();
        System.out.println("删除首尾后:" + link);
    }
}

//list存放自定义对象
import java.util.ArrayList;
import java.util.List;

// 自定义实体类
class User {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{name='" + name + "', age=" + age + "}";
    }
}

public class ListObject {
    public static void main(String[] args) {
        List<User> userList = new ArrayList<>();

        // 添加自定义对象
        userList.add(new User("小明", 20));
        userList.add(new User("小红", 18));

        // 遍历
        for (User user : userList) {
            System.out.println(user);
        }
    }
}

Set集合

特点:set是java.util下的集合接口,继承collecttion

三大核心特征

  1. 无序 :存取顺序不一致(部分实现类例外:LinkedHashSet 有序)
  2. 不可重复不能存储重复元素,自动去重
  3. 无索引没有下标 ,不能用普通 for 循环根据索引遍历

常用三大实现类

  • HashSet:底层哈希表,无序、不重复、查询最快,开发最常用
  • LinkedHashSet:底层哈希表 + 链表,有序(存取顺序一致)、不重复
  • TreeSet:底层红黑树,自然排序 / 自定义排序、不重复
**1.**HashSet
java 复制代码
//1.HashSet(开发最常用)
//特点:无序,不可重复,无索引
import java.util.HashSet;
import java.util.Set;

public class HashSetTest {
    public static void main(String[] args) {
        // 创建集合
        Set<String> set = new HashSet<>();

        // 添加元素
        set.add("张三");
        set.add("李四");
        set.add("王五");
        // 添加重复元素
        set.add("张三");

        // 打印:无序 + 自动去重
        System.out.println(set);
    }
}
//打印结果为[李四, 张三, 王五]
//HashSet 常用方法
import java.util.HashSet;
import java.util.Set;

public class HashSetMethod {
    public static void main(String[] args) {
        Set<Integer> set = new HashSet<>();

        // 添加
        set.add(10);
        set.add(20);
        set.add(10); // 重复,无效

        // 集合元素个数
        System.out.println("元素个数:" + set.size());

        // 判断是否包含某个元素
        System.out.println("是否包含20:" + set.contains(20));

        // 删除元素
        set.remove(10);
        System.out.println("删除后:" + set);

        // 判断是否为空
        System.out.println("是否为空:" + set.isEmpty());

        // 清空所有元素
        // set.clear();
    }
}
//Set遍历方式
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class SetForeach {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>();
        set.add("Java");
        set.add("MySQL");
        set.add("Vue");

        // 1. 增强for循环(最常用)
        for (String s : set) {
            System.out.println(s);
        }

        System.out.println("--------");

        // 2. 迭代器遍历
        Iterator<String> it = set.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }

        System.out.println("--------");

        // 3. Lambda 遍历(JDK8+)
        set.forEach(System.out::println);
    }
}
2.LinkedHashSet

特点:保留添加顺序,不可重复;

适合:既要去重,又要保证存入顺序和取出顺序一致

java 复制代码
import java.util.LinkedHashSet;
import java.util.Set;

public class LinkedHashSetTest {
    public static void main(String[] args) {
        Set<String> set = new LinkedHashSet<>();

        set.add("苹果");
        set.add("香蕉");
        set.add("橙子");
        set.add("苹果"); // 重复自动忽略

        // 输出顺序 = 添加顺序
        System.out.println(set);
    }
}
//输出  [苹果, 香蕉, 橙子]
3.TreeSet 自动排序集合

特点:不重复,默认升序排序

java 复制代码
import java.util.TreeSet;
import java.util.Set;

public class TreeSetTest {
    public static void main(String[] args) {
        Set<Integer> set = new TreeSet<>();

        set.add(5);
        set.add(1);
        set.add(9);
        set.add(1);

        // 自动从小到大排序
        System.out.println(set);
    }
}
//输出[1, 5, 9]

Map 键值对

特点:键唯一,值可重复;通过key快速找value;无索引,不能用普通for循环遍历

开发用得最多:接口传参,存配置,字典,下拉选项

常用实现类:

  • HashMap:无序、键唯一、效率最高(日常最常用)
  • LinkedHashMap有序、键唯一
  • TreeMap:按键自动排序
实现类 特点
HashMap 存取无序、键不重复、效率高
LinkedHashMap 存取有序、键不重复
TreeMap 按键自然排序、键不重复
HashMap
java 复制代码
//map基础使用(增删改查)
import java.util.HashMap;
import java.util.Map;

public class MapDemo1 {
    public static void main(String[] args) {
        // Map<键类型, 值类型>
        Map<String, Integer> map = new HashMap<>();

        // 1. 添加键值对 put(key,value)
        map.put("张三", 20);
        map.put("李四", 22);
        map.put("王五", 19);

        // 键重复,会覆盖原来的值
        map.put("张三", 25);

        // 打印整个Map
        System.out.println(map);

        // 2. 根据键获取值 get(key)
        Integer age = map.get("李四");
        System.out.println("李四年龄:" + age);

        // 3. 根据键删除键值对 remove(key)
        map.remove("王五");
        System.out.println("删除王五后:" + map);

        // 4. 判断是否包含指定键 / 值
        System.out.println("是否包含键 张三:" + map.containsKey("张三"));
        System.out.println("是否包含值 22:" + map.containsValue(22));

        // 5. 获取键值对个数
        System.out.println("元素个数:" + map.size());

        // 6. 清空集合
        // map.clear();

        // 7. 判断是否为空
        System.out.println("是否为空:" + map.isEmpty());
    }
}

//Map三种遍历方式(必掌握)
//方式1:先获取所有键,再通过键取值
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MapLoop1 {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("Java", 80);
        map.put("Python", 90);
        map.put("C++", 70);

        // 获取所有键,放到 Set 集合
        Set<String> keySet = map.keySet();

        // 遍历所有键
        for (String key : keySet) {
            // 通过键拿值
            Integer value = map.get(key);
            System.out.println(key + " = " + value);
        }
    }
}
//方式2:键值对对象遍历(推荐)
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MapLoop2 {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("语文", 95);
        map.put("数学", 98);
        map.put("英语", 92);

        // 获取所有键值对对象
        Set<Map.Entry<String, Integer>> entrySet = map.entrySet();

        for (Map.Entry<String, Integer> entry : entrySet) {
            String key = entry.getKey();
            Integer value = entry.getValue();
            System.out.println(key + " : " + value);
        }
    }
}
//Lambda 遍历(JDK8 简洁写法)
import java.util.HashMap;
import java.util.Map;

public class MapLoop3 {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        map.put("001", "小明");
        map.put("002", "小红");

        // 一行遍历
        map.forEach((k, v) -> System.out.println(k + "->" + v));
    }
}
LinkedHashMap

保留添加顺序,键不重复

java 复制代码
import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashMapDemo {
    public static void main(String[] args) {
        Map<String, Integer> map = new LinkedHashMap<>();

        map.put("A", 1);
        map.put("B", 2);
        map.put("C", 3);

        // 输出顺序和添加顺序一致
        System.out.println(map);
    }
}
TreeMap

按键默认升序排列

java 复制代码
import java.util.TreeMap;
import java.util.Map;

public class TreeMapDemo {
    public static void main(String[] args) {
        Map<String, Integer> map = new TreeMap<>();

        map.put("b", 2);
        map.put("a", 1);
        map.put("c", 3);

        // 按键字典顺序自动排序
        System.out.println(map);
    }
}

Map 存储自定义对象示例

java 复制代码
import java.util.HashMap;
import java.util.Map;

class User {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{name='" + name + "', age=" + age + "}";
    }
}

public class MapUserDemo {
    public static void main(String[] args) {
        Map<String, User> userMap = new HashMap<>();

        userMap.put("user1", new User("张三", 20));
        userMap.put("user2", new User("李四", 22));

        // 遍历
        userMap.forEach((k, v) -> System.out.println(k + " : " + v));
    }
}

链表 LinkedList

由一个个节点连起来,每个节点存【数据 + 下一个节点地址】,内存不连续,不用固定长度,插入删除极快。

数组:内存连续,靠下标访问。

链表:内存不连续,每个节点存数据+下一个节点地址

常见链表分类
  1. 单向链表:只能从头往后走
  2. 双向链表 :可以向前、向后遍历(Java LinkedList 就是双向链表)
  3. 循环链表:最后一个节点指向头节点
特性 数组 链表
内存 连续 不连续
查询 快(按索引 O (1)) 慢(从头遍历 O (n))
增删 慢(要移动元素) 快(只改引用指向)
长度 固定不可变 动态不限长度
浪费空间 可能浪费 每个节点多占指针空间

一句话:查多用数组 / ArrayList,频繁增删用链表 / LinkedList

java 复制代码
//基本使用代码
import java.util.LinkedList;

public class LinkTest {
    public static void main(String[] args) {
        // 创建链表
        LinkedList<String> list = new LinkedList<>();

        // 普通添加
        list.add("A");
        list.add("B");
        list.add("C");

        // 头部、尾部添加
        list.addFirst("开头");
        list.addLast("结尾");

        System.out.println(list);

        // 获取首尾
        System.out.println("第一个:" + list.getFirst());
        System.out.println("最后一个:" + list.getLast());

        // 删除首尾
        list.removeFirst();
        list.removeLast();

        System.out.println("操作后:" + list);
    }
}
//常用方法
add()         // 尾部加
addFirst()    // 头部加
addLast()     // 尾部加
getFirst()    // 拿第一个
getLast()     // 拿最后一个
removeFirst() // 删第一个
removeLast()  // 删最后一个
size()        // 元素个数
//遍历链表
// 增强for遍历
for (String s : list) {
    System.out.println(s);
}

栈 Stack / 队列 Queue

栈 Stack

特点:最后进去的,最先出来;

常用场景:函数调用,递归,括号匹配,浏览器后退,撤销操作。

java 复制代码
import java.util.LinkedList;

// 用 LinkedList 当栈用
public class StackDemo {
    public static void main(String[] args) {
        LinkedList<String> stack = new LinkedList<>();

        // 入栈(压栈)
        stack.push("第1个");
        stack.push("第2个");
        stack.push("第3个");

        System.out.println(stack);

        // 出栈:后进先出
        System.out.println(stack.pop()); // 第3个
        System.out.println(stack.pop()); // 第2个

        // 查看栈顶元素,不删除
        System.out.println(stack.peek()); // 第1个
    }
}

队列:先进先出

java 复制代码
import java.util.Queue;
import java.util.LinkedList;

public class QueueDemo {
    public static void main(String[] args) {
        Queue<String> queue = new LinkedList<>();
        queue.offer("一号");
        queue.offer("二号");
        System.out.println(queue.poll()); // 先出一号
    }
}
相关推荐
多加点辣也没关系1 小时前
数据结构与算法|第二十三章:高级数据结构
数据结构·算法
孬甭_3 小时前
初识数据结构与算法
数据结构
naturerun7 小时前
从数组中删除元素的算法
数据结构·c++·算法
酿情师10 小时前
区块链原理与技术02:区块链的数据结构04(区块结构)
数据结构·区块链
夏日听雨眠10 小时前
数据结构(循环队列)
数据结构·算法·链表
平行侠11 小时前
30MacLaren-Marsaglia算法故事文件
数据结构·算法
平行侠12 小时前
33水库抽样 - 从未知大小的流中等概率采样
数据结构·算法
Controller-Inversion12 小时前
42. 接雨水
数据结构·算法·leetcode