java数据结构与排序

java和c++还是有不同之处的,写个数据结构熟悉一下java

链表

复制代码
import java.util.Arrays;

public class arrlylist{
    private int[] elem;
    private int usedSize;
    private static final int array_size=10;
    public arrlylist(){
        this.elem = new int[array_size];
    }
    public void display(){
        System.out.println("Current list content:");
        for (int i = 0;i < this.usedSize;++i)
        {
            System.out.println(this.elem[i]);
        }
    }
    // Check if the list is full
    public boolean isFull() {
        return this.usedSize == this.elem.length;
    }
    // Add element at specified position
    public void add(int pos, int data) {
        // Check position validity
        if (pos < 0 || pos > usedSize) {
            System.out.println("Error: Invalid position!");
            return;
        }
        // Check if need to expand
        if (isFull()) {
            this.elem = Arrays.copyOf(this.elem, 2 * this.elem.length);
        }
        // Move elements after pos backward
        for (int i = usedSize - 1; i >= pos; i--) {
            this.elem[i + 1] = this.elem[i];
        }
        this.elem[pos] = data;
        this.usedSize++;
    }
    // Add element at the end (overloaded method)
    public void add(int data) {
        add(this.usedSize, data);
    }
    public static void main(String[] args) {
        System.out.println("hello arrlylist");
        arrlylist list=new arrlylist();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(1, 99); // Insert 99 at index 1
        list.display();  // Expected: [ 1, 99, 2, 3 ]
    }
}

二叉树

复制代码
import java.util.List;
import java.util.ArrayList;

class treenode{
    int val;
    treenode left;
    treenode right;
    public treenode(int val){
        this.val=val;
    }
}
public class tree{
    private treenode root = null;
    public void insert(int val)
    {
        if (root == null)
        {
            root = new treenode(val);
            return;
        }
        treenode cur = root;
        treenode parent = null;
        while (cur != null)
        {
            parent = cur;
            if (val < cur.val)
            {
                cur = cur.left;
            }
            else
            {
                cur = cur.right;
            }
        }
        if (val < parent.val)
        {
            parent.left = new treenode(val);
        }
        else
        {
            parent.right = new treenode(val);
        }
    }
    public List<treenode> preorder(treenode toor)
    {
        List<treenode> ret = new ArrayList<>();
        if (root == null) return ret;
        ret.add(toor);
        List<treenode> left = preorder(toor.left);
        ret.addAll(left);
        List<treenode> right = preorder(toor.right);
        ret.addAll(right);
        return ret;
    }
    public static void main(String[] args) {
        tree bst = new tree();
        
        // 自动插入,不需要手动连线
        int[] nodes = {50, 30, 70, 20, 40, 60, 80};
        System.out.println("依次插入: 50, 30, 70, 20, 40, 60, 80");
        
        for (int x : nodes) {
            bst.insert(x);
        }
    }
}

哈希和set

哈希主要是一个key对应一个value,哈希值是key通过哈希函数得到,用哈希值可以在一个数组中作为下标找到value,如果哈希值算出来重复的话是哈希冲突,在同一个value里对应的值加一个,下标位挂一个链表,如果太长用红黑树解决。

set利用了哈希表中key是唯一值的特点,用来存储不重复的数据

七大排序

复制代码
public class seven_sort{
    public void unsort(int[] arr){
        arr[6]=arr[0];
        arr[0]=arr[1];
        arr[1]=arr[2];
        arr[2]=arr[3];
        arr[3]=arr[4];
        arr[4]=arr[5];
        arr[5]=arr[6];
    }
    // 交换数组中两个元素的位置
    private void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
    //O(n^2)三剑客
    public void bubblesort(int[] arr){ // 冒泡排序 相邻比对,大的往后挪。每一趟能确定一个最大值到末尾。
        int n=arr.length;
        for(int i=0;i<n-1;i++){
            for(int j=0;j<n-1-i;j++){
                if(arr[j]>arr[j+1]){
                    int temp=arr[j];
                    arr[j]=arr[j+1];
                    arr[j+1]=temp;
                }
            }
        }
    }
    public void selectsort(int[] arr){//选择排序 定格位置,全场选最小
        for (int i = 0; i < arr.length - 1; i++) {
            int minIndex = i;
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[j] < arr[minIndex]) minIndex = j;
            }
            int temp = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] = temp;
        }
    }
    public void insertsort(int[] arr){//插入排序 待排元素插入到前面已经排好的有序序列中
        for (int i = 1; i < arr.length; i++) {
            int key = arr[i];
            int j = i - 1;
            while (j >= 0 && key < arr[j]) {
                arr[j + 1] = arr[j];
                j--;
            }
            arr[j + 1] = key;
        }
    }
    //改良排序
    public void shellSort(int[] arr) {//希尔排序 先按增量(gap)分组排序,最后再来一次全体插排。
        for (int gap = arr.length / 2; gap > 0; gap /= 2) {
            for (int i = gap; i < arr.length; i++) {
                int key = arr[i], j = i;
                while (j >= gap && arr[j - gap] > key) {
                    arr[j] = arr[j - gap];
                    j -= gap;
                }
                arr[j] = key;
            }
        }
    }
    public void heapSort(int[] arr) { //堆拿出最顶元素,然后最后的元素补到顶再重排成堆。利用二叉树的logn,减少计算量
    // 1. 建堆
        for (int i = arr.length / 2 - 1; i >= 0; i--) shiftDown(arr, i, arr.length);
        // 2. 交换并调整
        for (int i = arr.length - 1; i > 0; i--) {
            swap(arr, 0, i);
            shiftDown(arr, 0, i);
        }
    }
    private void shiftDown(int[] arr, int i, int n) {
        int temp = arr[i];
        for (int k = 2 * i + 1; k < n; k = 2 * k + 1) {
            if (k + 1 < n && arr[k] < arr[k + 1]) k++;
            if (arr[k] > temp) { arr[i] = arr[k]; i = k; }
            else break;
        }
        arr[i] = temp;
    }
    //分治排序法
    //快速排序
    public void quickSort(int[] arr, int left, int right) {//快速排序 选基准值(Pivot),小的放左,大的放右,递归进行。
        if (left >= right) return;
        int pivot = partition(arr, left, right);
        quickSort(arr, left, pivot - 1);
        quickSort(arr, pivot + 1, right);
    }

    private int partition(int[] arr, int left, int right) {
        int pivot = arr[left];
        while (left < right) {
            while (left < right && arr[right] >= pivot) right--;
            arr[left] = arr[right];
            while (left < right && arr[left] <= pivot) left++;
            arr[right] = arr[left];
        }
        arr[left] = pivot;
        return left;
    }
    //归并排序
    public void mergeSort(int[] arr, int l, int r) {//归并排序 先拆分到只剩一个数,再两两合并
        if (l >= r) return;
        if (l < r) {
            int m = l + (r - l) / 2;
            mergeSort(arr, l, m);
            mergeSort(arr, m + 1, r);
            merge(arr, l, m, r);
        }
    }

    private void merge(int[] arr, int l, int m, int r) {
        int[] temp = new int[r - l + 1];
        int i = l, j = m + 1, k = 0;
        while (i <= m && j <= r) temp[k++] = (arr[i] <= arr[j]) ? arr[i++] : arr[j++];
        while (i <= m) temp[k++] = arr[i++];
        while (j <= r) temp[k++] = arr[j++];
        System.arraycopy(temp, 0, arr, l, temp.length);
    }
    
    

    // 打印数组
    public void printArray(int[] arr, String description) {
        System.out.print(description + ": ");
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }
    
    public static void main(String[] args) {
        System.out.println("=== 七大排序算法测试 ===");
        seven_sort sorter = new seven_sort();
        
        // 测试数据
        int[] originalArr = {50, 30, 70, 20, 40, 60, 80};
        
        // 1. 冒泡排序
        int[] arr1 = originalArr.clone();
        sorter.printArray(arr1, "冒泡排序前");
        sorter.unsort(arr1);
        sorter.printArray(arr1, "打乱后");
        sorter.bubblesort(arr1);
        sorter.printArray(arr1, "冒泡排序后");
        System.out.println();
        
        // 2. 选择排序
        int[] arr2 = originalArr.clone();
        sorter.printArray(arr2, "选择排序前");
        sorter.unsort(arr2);
        sorter.printArray(arr2, "打乱后");
        sorter.selectsort(arr2);
        sorter.printArray(arr2, "选择排序后");
        System.out.println();
        
        // 3. 插入排序
        int[] arr3 = originalArr.clone();
        sorter.printArray(arr3, "插入排序前");
        sorter.unsort(arr3);
        sorter.printArray(arr3, "打乱后");
        sorter.insertsort(arr3);
        sorter.printArray(arr3, "插入排序后");
        System.out.println();
        
        // 4. 希尔排序
        int[] arr4 = originalArr.clone();
        sorter.printArray(arr4, "希尔排序前");
        sorter.unsort(arr4);
        sorter.printArray(arr4, "打乱后");
        sorter.shellSort(arr4);
        sorter.printArray(arr4, "希尔排序后");
        System.out.println();
        
        // 5. 堆排序
        int[] arr5 = originalArr.clone();
        sorter.printArray(arr5, "堆排序前");
        sorter.unsort(arr5);
        sorter.printArray(arr5, "打乱后");
        sorter.heapSort(arr5);
        sorter.printArray(arr5, "堆排序后");
        System.out.println();
        
        // 6. 快速排序
        int[] arr6 = originalArr.clone();
        sorter.printArray(arr6, "快速排序前");
        sorter.unsort(arr6);
        sorter.printArray(arr6, "打乱后");
        sorter.quickSort(arr6, 0, arr6.length - 1);
        sorter.printArray(arr6, "快速排序后");
        System.out.println();
        
        // 7. 归并排序
        int[] arr7 = originalArr.clone();
        sorter.printArray(arr7, "归并排序前");
        sorter.unsort(arr7);
        sorter.printArray(arr7, "打乱后");
        sorter.mergeSort(arr7, 0, arr7.length - 1);
        sorter.printArray(arr7, "归并排序后");
        System.out.println();
        
        System.out.println("=== 测试完成 ===");
    }
}

快速排序详解

1. 核心流程拆解

A. quickSort 方法 (分治递归)

这是一个典型的递归函数:

  1. 递归终止条件left >= right。当子区间只有一个数或没有数时,不需要排序。

  2. 划分区间 :调用 partition 找出基准值的准确位置 pivot

  3. 递归左右:对基准值左边的区间和右边的区间分别重复上述过程。

B. partition 方法 (挖坑填数)

这是快排最关键的逻辑,我们用一个例子演示:arr = [4, 7, 2, 5, 3]

  1. 选基准(挖坑) : 令 pivot = arr[left] (即 4)。此时,left 位置(下标0)被视为一个**"坑"**。

  2. 右指针左移 (right--) : 从右往左找一个比 4 小 的数。发现 34 小。

    • 填坑 :把 3 填到 left 的坑位。

    • 新坑 :此时 right 位置(下标4)变成了新坑。

  3. 左指针右移 (left++) : 从左往右找一个比 4 大 的数。发现 74 大。

    • 填坑 :把 7 填到 right 的坑位。

    • 新坑 :此时 left 位置(下标1)变成了新坑。

  4. 循环终止 : 当 left == right 时,说明所有数都比较过了,这个交汇点就是 pivot 该呆的位置。

  5. 回填基准 : 把最初的 4 填入 left 这个最后的坑里。

归并排序解释

1. 核心流程:分、治、合

A. 递归拆分 (mergeSort 方法)

代码中的 int m = l + (r - l) / 2; 是为了防止 (l + r) / 2 可能导致的整数溢出。

  1. 分(Divide):将数组从中间一分为二。

  2. 治(Conquer):递归地对左半部分和右半部分进行归并排序。

  3. 合(Combine) :当子序列被拆到只有一个元素时(l >= r),认为是有序的,开始向上合并。


B. 核心合并逻辑 (merge 方法)

这是归并排序的精华。它的任务是:将两个已经有序的子序列合并成一个新的、更大的有序序列。

  1. 开辟辅助空间int[] temp = new int[r - l + 1];。归并排序不是原地排序,它需要额外的 O(n) 空间。

  2. 双指针赛跑

    • i 指向左半区起始,j 指向右半区起始。

    • 比较 arr[i]arr[j],谁小就把谁塞进 temp,然后对应的指针后移。

  3. 善后工作

    • 当其中一个半区跑完后,另一个半区可能还剩下一些数。

    • 接下来的两个 while 循环就是把剩下的"有序尾巴"直接搬进 temp

  4. 写回原数组 :使用 System.arraycopy 将排好序的 temp 覆盖回原数组 arr 的对应区间 [l, r]

反射枚举lambda表达式

反射类可以调用私有的类的构造方法,但是开销更大,是一把双刃剑

反射无法读取枚举,枚举的单例是最安全的

1. 反射 (Reflection)

核心概念

反射允许程序在运行时 (Runtime) 取得任何类的内部信息(如成员变量、方法、构造器),并能直接操作任意对象的内部属性及方法。它是 Java 被称为"动态语言"的关键。

主要功能

  • 在运行时判断任意一个对象所属的类。

  • 在运行时构造任意一个类的对象。

  • 在运行时获取/调用任意一个类所具有的成员变量和方法。

代码示例

Java

复制代码
// 获取 Class 对象的三种方式
Class<?> c1 = Class.forName("com.example.User"); // 最常用
Class<?> c2 = User.class;
Class<?> c3 = userInstance.getClass();

// 动态创建对象并调用方法
Object obj = c1.getDeclaredConstructor().newInstance();
Method method = c1.getMethod("sayHello");
method.invoke(obj); // 执行方法

优缺点

  • 优点: 极高的灵活性。它是所有框架(Spring, MyBatis 等)的底层基石(例如:Spring 的 IOC 容器就是通过反射读取配置并生成对象的)。

  • 缺点: 性能开销大(比直接调用慢);破坏了封装性(可以强制访问 private 属性)。


2. 枚举 (Enum)

核心概念

枚举是一种特殊的类(Class),用于定义一组固定的常量。在 Java 中,枚举不仅仅是数字的别名,它是一个完整的对象,可以拥有字段、方法和构造器。

主要特点

  • 类型安全: 编译器会检查类型,不能随意赋值。

  • 单例模式: 枚举是实现单例模式最简单、最安全的方式(防止反射攻击)。

  • 继承性: 所有枚举都自动继承 java.lang.Enum,因此不能再继承其他类,但可以实现接口。

代码示例

Java

复制代码
public enum StatusCode {
    SUCCESS(200, "操作成功"),
    ERROR(500, "服务器错误");

    private final int code;
    private final String msg;

    // 构造器默认是 private
    StatusCode(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public int getCode() { return code; }
}

// 使用
StatusCode status = StatusCode.SUCCESS;
if (status == StatusCode.SUCCESS) {
    System.out.println(status.getCode()); // 输出 200
}

3. Lambda 表达式

核心概念

Lambda 是 Java 8 引入的新特性,用于简化函数式接口(只有一个抽象方法的接口)的实现。它让代码更简洁,并支持函数式编程风格。

核心语法

(参数列表) -> { 方法体 }

主要应用

  1. 简化匿名内部类: 尤其是 RunnableComparator 等接口。

  2. Stream API: 配合集合流式处理(过滤、映射、排序)。

代码示例

Java

复制代码
// 1. 传统方式 vs Lambda
// 传统匿名内部类
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Running...");
    }
}).start();

// Lambda 写法
new Thread(() -> System.out.println("Running...")).start();

// 2. 配合 Stream 处理集合
List<String> list = Arrays.asList("Java", "Python", "C++");
list.stream()
    .filter(s -> s.startsWith("J")) // 筛选以 J 开头的
    .map(String::toUpperCase)       // 转大写
    .forEach(System.out::println);  // 输出

总结对比

特性 核心作用 关键词 一句话记忆
反射 动态性 Class, Method, invoke "运行时扒开类的皮,直接操作内部。"
枚举 规范性 enum, values() "一组天然的、带属性的单例常量。"
Lambda 简洁性 ->, FunctionalInterface "把代码块像数据一样传递,消灭样板代码。"
相关推荐
木辰風4 小时前
PLSQL自定义自动替换(AutoReplace)
java·数据库·sql
2501_944525544 小时前
Flutter for OpenHarmony 个人理财管理App实战 - 预算详情页面
android·开发语言·前端·javascript·flutter·ecmascript
heartbeat..4 小时前
Redis 中的锁:核心实现、类型与最佳实践
java·数据库·redis·缓存·并发
Prince-Peng4 小时前
技术架构系列 - 详解Redis
数据结构·数据库·redis·分布式·缓存·中间件·架构
5 小时前
java关于内部类
java·开发语言
好好沉淀5 小时前
Java 项目中的 .idea 与 target 文件夹
java·开发语言·intellij-idea
gusijin5 小时前
解决idea启动报错java: OutOfMemoryError: insufficient memory
java·ide·intellij-idea
To Be Clean Coder5 小时前
【Spring源码】createBean如何寻找构造器(二)——单参数构造器的场景
java·后端·spring
lsx2024065 小时前
FastAPI 交互式 API 文档
开发语言
吨~吨~吨~5 小时前
解决 IntelliJ IDEA 运行时“命令行过长”问题:使用 JAR
java·ide·intellij-idea