Green Project Eight

1.分别持久化基本数据类型以及对象类型到本地文件

ID生成器

package com.sanqi;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;

public class IdGenerator {
    private static final String DATA_DIR = "current";
    private static final String DATA_FILE = DATA_DIR+"/id_generator.dat";
    private static final long DEFAULT_VALUE = 1L;

    public static long getID() {
        synchronized (IdGenerator.class) {  // 添加同步锁
            long id;
            try {
                ensureDirectoryExists();
                File file = new File(DATA_FILE);
                if (!file.exists() || file.length() == 0) {
                    // 第一次使用或文件为空
                    id=DEFAULT_VALUE;
                    write(id + 1);//写入下一个id
                    return DEFAULT_VALUE;
                } else {
                    id = read();     // 读取当前ID值
                    write(id + 1);  // 更新为下一个ID
                    return id;
                }
            } catch (IOException e) {
                //Print relevant logs
                return -1;
            }
            }
    }
    private static void ensureDirectoryExists() throws IOException {
        Files.createDirectories(Paths.get(DATA_DIR));
    }
    private static long read() throws IOException {
        long id;
        try (DataInputStream dis = new DataInputStream(new FileInputStream(DATA_FILE))) {
            id = dis.readLong();
        }
        return id;
    }

    private static void write(long id) throws IOException {
        try (DataOutputStream dos =
                     new DataOutputStream(new FileOutputStream(DATA_FILE))) {
            dos.writeLong(id);
        }
    }
}

对象持久化工具类

package com.sanqi;

import java.io.*;

public class ObjectPersistUtil {
    private static final String DATA_FILE = "current/employee_data.dat";
    public static int persist(Object instance) {
        try (ObjectOutputStream oos =
                     new ObjectOutputStream(
                             new FileOutputStream(DATA_FILE))) {
            oos.writeObject(instance);
            return 1;
        }catch (IOException e){
           //Print relevant logs
        }
        return -1;
    }
    public static Employee read(){
        Employee stu =null;
        File file=new File(DATA_FILE);
        if(!file.exists()){
            return stu;
        }
        try (ObjectInputStream ois =
                     new ObjectInputStream(
                             new FileInputStream(file));) {
            stu=(Employee) ois.readObject();
        }catch (IOException |ClassNotFoundException e){
            //Print relevant logs
        }
        return stu;
    }
}

对象类

package com.sanqi;

import java.io.Serializable;
import java.time.LocalDate;
import java.util.Objects;
//需要实现Serialization接口
public class Employee implements Serializable {
    private  long id;
    private  String name;
    private  transient String phone;//transient表明不会被序列化
    private  char gender;
    private LocalDate birth;

    public long getId() {
        return id;
    }
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }

    public LocalDate getBirth() {
        return birth;
    }

    public void setBirth(LocalDate birth) {
        this.birth = birth;
    }

    public Employee() {
        this.id=IdGenerator.getID();
    }

    public Employee(String name, String phone, char gender, LocalDate birth) {
        this.name = name;
        this.phone = phone;
        this.gender = gender;
        this.birth = birth;
        this.id=IdGenerator.getID();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return id == employee.id && Objects.equals(name, employee.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name);
    }

    @Override
    public String toString() {
        final StringBuilder s = new StringBuilder("Employee{");
        s.append("id=").append(id);
        s.append(", name='").append(name).append(''');
        s.append(", phone='").append(phone).append(''');
        s.append(", gender=").append(gender);
        s.append(", birth=").append(birth);
        s.append('}');
        return s.toString();
    }
}

主方法

package com.sanqi;

import java.io.File;
import java.time.LocalDate;

public class Main {
    public static void main(String[] args) {
        // 先清理旧文件
        cleanOldFiles();
        System.out.println("=== 测试ID生成 ===");
        for (int i = 0; i < 10; i++) {
            long id=IdGenerator.getID();
            System.out.println(id);
        }
        System.out.println("
=== 测试对象持久化 ===");
        Employee s=new Employee("37方寸","12345678901",'男', LocalDate.of(2001,8,3));
        System.out.println("原始对象: " + s);
        //对象持久化
        if(ObjectPersistUtil.persist(s)>0){
            System.out.println("持久化成功");
        }
        Employee employee=ObjectPersistUtil.read();
        System.out.println("读取到的信息"+employee);
    }

    private static void cleanOldFiles() {
        new File("current/id_generator.dat").delete();
        new File("current/employee_data.dat").delete();
        System.out.println("已清理旧文件");
    }
}

运行结果如下:

Green Project Eight

2.假定有一个巨大的文件,我们如何快速地读到此文件中的最后一行?

方法类

package com.sanqi;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.charset.StandardCharsets;

public class UseRandomAccessFile {
    public String readLastLine(String path) {
        try {
            RandomAccessFile raf = new RandomAccessFile(new File(path), "r");
            long len = raf.length();
            if (len == 0) {
                return "";
            }
            // 从最后一个字节开始往回遍历,寻找第一个换行符
            long pos = len - 1;
            raf.seek(pos);
            while (pos > 0) {
                pos--;
                raf.seek(pos);
                if (raf.readByte() == '
') {
                    break;
                }
            }
            if (pos == 0) {
                raf.seek(0);
            }
            byte[] bytes = new byte[(int) (len - pos)];
            raf.read(bytes);
            String line = new String(bytes, StandardCharsets.UTF_8);
            // 移除末尾的

            if (line.endsWith("
")) {
                line = line.substring(0, line.length() - 1);
            }
            return line.trim();
        } catch (IOException e) {
            // Print logs
            return null;
        }
    }

}

主方法

package com.sanqi;

public class Main {
    public static void main(String[] args) {
        UseRandomAccessFile reader = new UseRandomAccessFile();
        String path = "D:桌面2025_11_02test.txt";
        String lastLine = reader.readLastLine(path);
        System.out.println("最后一行内容: " + lastLine);
    }
}

运行结果如下:

Green Project Eight

Green Project Eight

3.实现二叉搜索树的增删改查

节点数据结构:

package com.sanqi;

import java.util.Objects;

public class Node<T extends Comparable<T> > {
    private T data;
    private Node<T> left;
    private Node<T> right;
    public Node(T data) {
        this.data = data;
    }
    public T getData() {
        return data;
    }
    public void setData(T data) {
        this.data = data;
    }
    public Node<T> getLeft() {
        return left;
    }
    public void setLeft(Node<T> left) {
        this.left = left;
    }
    public Node<T> getRight() {
        return right;
    }
    public void setRight(Node<T> right) {
        this.right = right;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Node<?> node = (Node<?>) o;
        return Objects.equals(data, node.data);
    }

    @Override
    public int hashCode() {
        return Objects.hash(data);
    }
}

二叉搜索树的接口:

package com.sanqi;

public interface Tree<T extends Comparable<T>> {
    void add(T data);
    void remove(T element);
    Node<T> findTargetNode(T element);
    void preOrder();
    void midOrder();
    void postOrder();
    int size();
}

二叉搜索树的实现类:

package com.sanqi;

public class BinarySearchTree<T extends Comparable<T>> implements Tree<T>  {
    private Node<T> root;
    private int size;
    @Override
    public void add(T data) {
        if (this.root == null) {
            this.root = new Node<>(data);
            this.size++;
            return;
        }
        Node<T> parent = null;//我们要找的目标节点
        Node<T> cur = this.root;//当前的节点,从跟开始找
        while (cur != null) {
            if (data.compareTo(cur.getData()) > 0) {
                parent = cur;
                cur = cur.getRight();
            } else if (data.compareTo(cur.getData()) < 0) {
                parent = cur;
                cur = cur.getLeft();
            } else {
                //说明我们要添加的元素与已有的元素一样了,根据BST的规则,则此元素添加不进来
                return;
            }
        }
        //3.在第二步的基础上,决定存放在左边还是右边
        if (data.compareTo(parent.getData()) > 0) {
            parent.setRight(new Node<>(data));
        } else {
            parent.setLeft(new Node<>(data));
        }
        this.size++;
    }

    @Override
    public void remove(T element) {
        //获取当前元素所在的节点
        Node<T>target=findTargetNode(element);
        if(target==null){
            System.out.println("没有找到" + element + "元素");
            return;
        }
        //获取当前元素所在节点的父节点
        Node<T>targetParent=findParentNode(element);
        //获取当前元素的右孩子中,最小的节点
        Node<T>minRight_of_target=findMinNodeFromRight(target);

        //下面分四种情况讨论
        //1.BST中只有一个根节点,并且此根节点就是我们要找的元素
            if (this.root == target&& target.getLeft() == null && target.getRight() == null) {
                this.root = null;
                this.size--;
                System.out.println("删除元素" + element + "成功");
            }
            //2.被删除元素在BST中是叶子节点
            if (target.getLeft() == null && target.getRight() == null) {
                 if (targetParent.getLeft() == target) {
                     targetParent.setLeft(null);
                 } else {
                     targetParent.setRight(null);
                 }
                this.size--;
                System.out.println("删除元素" + element + "成功");
            }
            //3.被删除元素在BST中不是叶子节点,但是只有一个子节点,这个子节点可以是左孩子或是右孩子
            //左孩子的情况
            else if (target.getLeft() == null || target.getRight() == null) {
                //将该节点的父节点指向该节点的子孩子
                Node<T>child=target.getLeft()==null?target.getRight():target.getLeft();
                if (targetParent!= null) {
                    if (targetParent.getLeft() == target) {
                        targetParent.setLeft(child);
                    } else {
                        targetParent.setRight(child);
                    }
                }
                else {//说明target是根节点
                    this.root=child;
                }
                this.size--;
                System.out.println("删除元素" + element + "成功");
            }

            //4.被删除元素在BST中不是叶子节点,而且拥有左右子孩子。
            else {
                T temp=minRight_of_target.getData();
                remove(minRight_of_target.getData());
                target.setData(temp);
                this.size--;
                System.out.println("删除元素" + element + "成功");
            }
    }
    /** 辅助方法一:查询元素,找到的话,返回元素所在的节点,如果找不到,则返回null*/
    @Override
    public Node<T> findTargetNode(T element) {
        Node<T> cur = this.root;//当前的节点,从跟开始找
        while (cur != null) {
            if (element.compareTo(cur.getData()) > 0) {
                //往右边去找
                cur = cur.getRight();
            } else if (element.compareTo(cur.getData()) < 0) {
                //往左边去找
                cur = cur.getLeft();
            } else {
                //查找成功
                return cur;
            }
        }
        return null;
    }

    /** 辅助方法二:查询元素,找到的话,返回元素所在的节点的父节点,如果找不到,则返回null*/
    public Node<T> findParentNode(T target){
        Node<T> parent = null;//当前的节点,从跟开始找
        Node<T> cur = this.root;//当前的节点,从跟开始找
        while (cur != null) {
            if (target.compareTo(cur.getData()) > 0) {
                //往右边去找
                parent=cur;
                cur = cur.getRight();
            } else if (target.compareTo(cur.getData()) < 0) {
                //往左边去找
                parent=cur;
                cur = cur.getLeft();
            } else {
                //查找成功
                return parent;
            }
        }
        return null;
    }

    /** 辅助方法三://从目标节点的右孩子中,找出最小的节点*/
    public Node<T> findMinNodeFromRight(Node<T> target){
        if(target!=null&&target.getRight()!=null) {
            //定义目标节点的右孩子
            Node<T> minright_of_target = target.getRight();
            //从目标节点的右孩子中,找出最小的节点
            while (minright_of_target.getLeft() != null) {
                minright_of_target = minright_of_target.getLeft();
            }
            return minright_of_target;
        }
        return null;
    }

    /**前序遍历*/
    @Override
    public void preOrder() {
        preOrder(this.root);
    }
    private void preOrder(Node<T> tree) {
        if (tree == null) {
            return;
        }
        System.out.println(tree.getData() + " ");
        preOrder(tree.getLeft());
        preOrder(tree.getRight());
    }

    /**中序遍历*/
    @Override
    public void midOrder() {
        midOrder(this.root);
    }
    private void midOrder(Node<T> tree) {
        if (tree == null) {
            return;
        }
        midOrder(tree.getLeft());
        System.out.println(tree.getData() + " ");
        midOrder(tree.getRight());
    }

    /**后序遍历*/
    @Override
    public void postOrder() {
      postOrder(this.root);
    }
    private void postOrder(Node<T> tree) {
        if (tree == null) {
            return;
        }
        postOrder(tree.getLeft());
        postOrder(tree.getRight());
        System.out.println(tree.getData() + " ");
    }
    /**返回树中结点的数量 */
    @Override
    public int size() {
        return this.size;
    }

}

模拟实体类

package com.sanqi;

import java.util.Objects;


public class Person implements Comparable<Person> {
    private  String name;
    private  int age;
    private  char sex;
    private  String phone;
    private  String address;

    public Person(String name, int age, char sex, String phone, String address) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.phone = phone;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    @Override
    public int compareTo(Person other) {
    //按照姓名和年龄进行比较,如年龄一样,就按姓名比较,如果都一样,则认为是“一样”的对象。
        if(this.getAge()==other.getAge()){
            return this.getName().compareTo(other.getName());
        }else return this.getAge()-other.getAge();
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Person{");
        sb.append("姓名是'").append(name).append(''');
        sb.append(", 年龄是").append(age).append('岁');
        sb.append(", 性别是").append(sex);
        sb.append(", 电话号码是'").append(phone).append(''');
        sb.append(", 地址是'").append(address).append(''');
        sb.append('}');
        return sb.toString();
    }
}

创造实体类对应的业务类,聚合二叉搜索树

package com.sanqi;

public class PersonService {
    private final BinarySearchTree<Person> persons;
    public PersonService() {
        this.persons = new BinarySearchTree<>();
    }

    public void save(Person p){
        persons.add(p);
    }
    public void printAllPerson() {
         persons.midOrder();
    }
    public void delete(Person p) {
        persons.remove(p);
    }
    public void count(){
        System.out.println("目前一共拥有"+persons.size()+"名教师");
    }
}

①单独测试二叉搜索树

package com.sanqi;

public class UseBSTree {
    public static void main(String[] args) {
        BinarySearchTree<Integer> bst=new BinarySearchTree<>();
        bst.add(40);
        bst.add(14);
        bst.add(20);
        bst.add(18);
        bst.add(65);
        bst.add(4);
        bst.add(6);
        bst.add(17);
        bst.add(30);
        bst.add(23);
        System.out.println("BST中元素的个数:"+bst.size());
        System.out.println("-----前序遍历-----");
        bst.preOrder();
        System.out.println("
-----中序遍历-----");
        bst.midOrder();
        System.out.println("
-----后序遍历-----");
        bst.postOrder();
        bst.remove(13);
        bst.remove(17);
    }
}

②测试聚合二叉搜索树

package com.sanqi;

public class Test {
    public static void main(String[] args) {
        PersonService personService=new PersonService();
        Person p1 = new Person("Alice", 30, '女', "123-456-7890", "123 Main St");
        Person p2 = new Person("Bob", 25, '男', "098-765-4321", "456 Elm St");
        Person p3 = new Person("Charlie", 35, '男', "555-123-4567", "789 Oak St");
        Person p4 = new Person("Diana", 28, '女', "555-765-4321", "321 Maple St");
        Person p5 = new Person("Eve", 22, '女', "555-987-6543", "654 Pine St");
        Person p6 = new Person("Frank", 40, '男', "555-654-0987", "987 Cedar St");
        Person p7 = new Person("Grace", 33, '女', "555-321-8765", "213 Birch St");
        Person p8 = new Person("Hank", 45, '男', "555-876-5432", "435 Spruce St");
        personService.save(p1);
        personService.save(p2);
        personService.save(p3);
        personService.save(p4);
        personService.save(p5);
        personService.save(p6);
        personService.save(p7);
        personService.save(p8);
        personService.count();
        personService.printAllPerson();
        personService.delete(p5);
        personService.count();
    }
}

4.利用TreeMap实现一个学生成绩管理系统

学生实体记录类

package com.sanqi;

public record Student(String name, int score) {
    @Override
    public String toString() {
        return String.format("%s: %d分", name, score);
    }
}

TreeMap实现系统功能

package com.sanqi;
import java.util.*;

public class StudentGradeSystem {
    private final TreeMap<String, Student> nameMap;  // 按姓名排序
    private final TreeMap<Integer, List<Student>> scoreMap; // 按分数排序(倒序)

    public StudentGradeSystem() {
        nameMap = new TreeMap<>();
        scoreMap = new TreeMap<>(Comparator.reverseOrder()); // 分数从高到低
    }
    public void addStudent(Student student) {
        nameMap.put(student.name(), student);
        scoreMap.computeIfAbsent(student.score(), k->new ArrayList<>()).add(student);
    }
    public List<Student> getStudentsByNameRange(String from, String to) {
        // 自动比较并交换,确保 from <= to
        String actualFrom = from.compareTo(to) <= 0 ? from : to;
        String actualTo = from.compareTo(to) <= 0 ? to : from;

        SortedMap<String, Student> subMap = nameMap.subMap(actualFrom, true, actualTo, true);
        return new ArrayList<>(subMap.values());
    }
    public List<Student> getStudentsByScoreRange(int minScore, int maxScore) {
        List<Student> result = new ArrayList<>();
        NavigableMap<Integer, List<Student>> rangeMap =
                scoreMap.subMap(maxScore, true, minScore, true);

        for (List<Student> students : rangeMap.values()) {
            result.addAll(students);
        }
        return result;
    }

    public int getStudentRank(String name) {
        if (!nameMap.containsKey(name)) return -1;

        int targetScore = nameMap.get(name).score();
        int rank = 1;

        // 遍历分数更高的学生
        for (Map.Entry<Integer, List<Student>> entry : scoreMap.entrySet()) {
            if (entry.getKey() > targetScore) {
                rank += entry.getValue().size();
            } else {
                break;
            }
        }
        return rank;
    }

    /**
     * 获取前N名学生
     */
    public List<Student> getTopNStudents(int n) {
        List<Student> topN = new ArrayList<>();
        for (List<Student> students : scoreMap.values()) {
            for (Student student : students) {
                if (topN.size() >= n) break;
                topN.add(student);
            }
            if (topN.size() >= n) break;
        }
        return topN;
    }

    /**
     * 获取后N名学生(倒数N名)
     */
    public List<Student> getBottomNStudents(int n) {
        // 创建正序的分数视图
        NavigableMap<Integer, List<Student>> ascendingMap = scoreMap.descendingMap();
        List<Student> bottomN = new ArrayList<>();

        for (List<Student> students : ascendingMap.values()) {
            for (Student student : students) {
                if (bottomN.size() >= n) break;
                bottomN.add(student);
            }
            if (bottomN.size() >= n) break;
        }
        return bottomN;
    }
    public void displayAllByName() {
        System.out.println("=== 按姓名排序 ===");
        nameMap.values().forEach(System.out::println);
    }
    public void displayAllByScore() {
        System.out.println("=== 按分数排序 ===");
        scoreMap.values().stream()
                .flatMap(List::stream)
                .forEach(System.out::println);
    }
}

测试类

package com.sanqi;

public class TreeMapTest {
    public static void main(String[] args) {
        StudentGradeSystem system = new StudentGradeSystem();

        // 添加测试数据
        system.addStudent(new Student("张三", 85));
        system.addStudent(new Student("李四", 92));
        system.addStudent(new Student("王五", 78));
        system.addStudent(new Student("赵六", 88));
        system.addStudent(new Student("钱七", 95));
        system.addStudent(new Student("孙八", 82));
        system.addStudent(new Student("周九", 90));

        System.out.println("1. 所有学生(按姓名排序):");
        system.displayAllByName();

        System.out.println("
2. 所有学生(按分数排序):");
        system.displayAllByScore();

        System.out.println("
3. 查询80-90分的学生:");
        system.getStudentsByScoreRange(80, 90).forEach(System.out::println);

        System.out.println("
4. 查询姓名在'李'到'孙'之间的学生:");
        system.getStudentsByNameRange("李", "孙").forEach(System.out::println);

        System.out.println("
5. 学生排名查询:");
        System.out.println("张三的排名:" + system.getStudentRank("张三"));
        System.out.println("李四的排名:" + system.getStudentRank("李四"));

        System.out.println("
6. 前三名学生:");
        system.getTopNStudents(3).forEach(System.out::println);

        System.out.println("
7. 后两名学生:");
        system.getBottomNStudents(2).forEach(System.out::println);
    }
}
© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
实验室咨询的头像 - 鹿快
评论 抢沙发

请登录后发表评论

    暂无评论内容