Java数据结构

数据结构

数据结构包括:线性结构和非线性结构

线性结构

  1. 线性结构作为最常用的数据结构,其特点是数据元素之间存在一对一的线性关系
  2. 线性结构有两种不同的存储结构,即顺序存储结构(数组)链式存储结构(链表)。顺序存储的线性表称为顺序表,顺序表中的存储元素是连续的
  3. 链式存储的线性表称为链表,链表中的存储元素不一定是连续的,元素节点中存放数据元素以及相邻元素的地址信息
  4. 线性结构常见的有:数组、队列、链表和栈

非线性结构

非线性结构包括:二维数组、多维数组、广义表、树结构、图结构

稀疏数组

基本介绍

当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组

稀疏数组的处理方法是:

  1. 记录数组一共有几行几列,有多少不同的值
  2. 把具有不同值的元素的行列及值记录在一个小规模的数组中,从而缩小程序的规模

Java数据结构_第1张图片

Java数据结构_第2张图片

package com.yhs.sparsearray;

import java.io.*;

public class SparseArray {
   
    public static void main(String[] args) throws IOException {
   
        //创建一个二维数组 11 * 11
        int[][] chessArr1 = new int[11][11];
        chessArr1[1][2] = 1;
        chessArr1[2][3] = 2;
        chessArr1[4][5] = 2;
        //输出原始的二维数组
        System.out.println("原始的二维数组");
        for (int[] row : chessArr1) {
   
            for (int data : row) {
   
                System.out.print(data + "\t");
            }
            System.out.println();
        }

        //将原始数组转稀疏数组
        //1. 先遍历二维数组 得到非0数据的个数
        int sum = 0;
        for (int i = 0; i < chessArr1.length; i++) {
   
            for (int j = 0; j < chessArr1.length; j++) {
   
                if (chessArr1[i][j] != 0) {
   
                    sum++;
                }
            }
        }

        //2. 创建对应的稀疏数组
        int sparseArr[][] = new int[sum + 1][3];
        // 给稀疏数组赋值
        sparseArr[0][0] = 11;
        sparseArr[0][1] = 11;
        sparseArr[0][2] = sum;

        // 遍历二维数组,将非零的值存放到稀疏数组
        int count = 0; //用来记录是第几个非零数据
        for (int i = 0; i < chessArr1.length; i++) {
   
            for (int j = 0; j < chessArr1.length; j++) {
   
                if (chessArr1[i][j] != 0) {
   
                    count++;
                    sparseArr[count][0] = i;
                    sparseArr[count][1] = j;
                    sparseArr[count][2] = chessArr1[i][j];
                }
            }
        }

        //输出稀疏数组的形式
        System.out.println();
        System.out.println("得到的稀疏数组为");
        for (int i = 0; i < sparseArr.length; i++) {
   
            System.out.printf("%d\t%d\t%d\t\n", sparseArr[i][0], sparseArr[i][1], sparseArr[i][2]);
        }
        System.out.println();

        //将稀疏数组 --> 恢复成原始的二维数组
        //读取稀疏数组后几行数据,并赋值给原始数组
        //1. 先读取稀疏数组第一行,得到原始数组的大小
        int[][] chessArr2 = new int[sparseArr[0][0]][sparseArr[0][1]];
        for (int i = 1; i < sparseArr.length; i++) {
   
            chessArr2[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
        }
        //输出恢复后的二维数组
        System.out.println();
        System.out.println("恢复后的二维数组");
        for (int[] row : chessArr2) {
   
            for (int data : row) {
   
                System.out.print(data + "\t");
            }
            System.out.println();
        }

        //将稀疏数组写入文件
        System.out.println("稀疏数组写入map.data文件");
        String filePath = "d:\\map.data";
        File file = new File(filePath);
        OutputStreamWriter writer = null;
        try {
   
            System.out.println("文件创建成功");
            writer = new OutputStreamWriter(new FileOutputStream(file), "GB2312");
        } catch (IOException e) {
   
            throw new RuntimeException(e);
        }
        for (int i = 0; i < sparseArr.length; i++) {
   
            if (i == sparseArr.length - 1) {
   
                writer.write(sparseArr[i][0] + "," + sparseArr[i][1] + "," + sparseArr[i][2]);
            } else {
   
                writer.write(sparseArr[i][0] + "," + sparseArr[i][1] + "," + sparseArr[i][2] + ",");
            }
        }
        writer.close();
        System.out.println("写入成功");


        //稀疏数组转二维数组首先读取文件
        InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(file));
        StringBuffer sbf = new StringBuffer();
        while (inputStreamReader.ready()) {
   
            sbf.append((char) inputStreamReader.read());
        }
        System.out.println("读出文件" + sbf.toString());
        inputStreamReader.close();

        //把读出的文件,赋值给稀疏数组
        String[] data = sbf.toString().split(",");
        System.out.println(data.length / 3);
        int[][] sparseArray2 = new int[data.length / 3][3];
        int i = 0;
        for (String s : data) {
   
            System.out.println(i % 3);
            sparseArray2[i / 3][i % 3] = Integer.parseInt(s);
            i++;
        }

        //输出读取到的稀疏数组
        System.out.println("读取到的稀疏数组如下++++++++++++");
        for (int j = 0; j < sparseArray2.length; j++) {
   
            System.out.print(sparseArray2[j][0] + "\t" + sparseArray2[j][1] + "\t" + sparseArray2[j][2]);
            System.out.println();
        }

        //1. 先读取稀疏数组的第一行,找出二维数组的大小
        int[][] charArray2 = new int[sparseArray2[0][0]][sparseArray2[0][1]];
        //2. 读取稀疏数组的值,给到二维数组
        for (int k = 1; k < sparseArray2.length; k++) {
   
            charArray2[sparseArray2[k][0]][sparseArray2[k][1]] = sparseArray2[k][2];
        }
        System.out.println("恢复后的二维数组");
        for (int[] row : charArray2) {
   
            for (int ds : row) {
   
                System.out.print(ds + "\t");
            }
            System.out.println();
        }
    }
}

队列

基本介绍

对列是一个有序列表,可以用数组链表来实现

遵循先入先出的原则,即:先存入队列的数据,要 先取出,后存入队列的数据,要后退出

数组模拟队列

Java数据结构_第3张图片

当我们将数据存入队列时称为“addQueue", “addQueue” 的处理需要有两个步骤;

  1. 将尾指针往后移:rear+1,当front == rear【空】
  2. 若尾指针 rear 小于队列的最大下标 maxSize -1 ,则将数据存入 rear所指的数组元素中,否则无法存入数组。rear == maxSize -1【队列满】

代码实现

package com.yhs.queue;

import java.util.Scanner;

public class Queue {
   
    public static void main(String[] args) {
   
        ArrayQueue arrayQueue = new ArrayQueue(3);
        char key = ' ';
        Scanner scanner = new Scanner(System.in);
        boolean loop = true;
        //输出一个菜单
        while (loop) {
   
            System.out.println("s(show): 显示队列");
            System.out.println("e(exit): 退出程序");
            System.out.println("a(add): 添加数据到队列");
            System.out.println("g(get): 从队列取出数据");
            System.out.println("h(head): 查看队列头的数据");
            System.out.print("请输入你的选择: ");
            key = scanner.next().charAt(0);
            switch (key) {
   
                case 's':
                  arrayQueue.showQueue();
                  break;
                case 'a':
                    System.out.print("请输入添加的数据: ");
                    int value = scanner.nextInt();
                    arrayQueue.addQueue(value);
                    break;
                case 'g':
                    try {
   
                        int res = arrayQueue.getQueue();
                        System.out.printf("取出的数据是%d\n", res);
                    } catch (Exception e) {
   
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h':
                    try {
   
                        int res = arrayQueue.headQueue();
                        System.out.printf("取出的头数据=%d\n", res);
                    } catch (Exception e) {
   
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e':
                    scanner.close();
                    loop = false;
                    break;
                default:
                    break;
            }
        }
        System.out.println("程序退出");
    }
}

//使用数组模拟队列编写一个ArrayQueue类
class ArrayQueue {
   
    private int maxSize; //表示数组最大容量
    private int front; //队列头
    private int rear; //队列尾
    private int[] arr; //该数组用于存放数据,模拟队列

    //添加构造器
    public ArrayQueue(int arrMaxsize) {
   
        maxSize = arrMaxsize;
        arr = new int[maxSize];
        front = -1; //指向队列头部,front指向队列头的前一个位置
        rear = -1; //指向队列尾部,指向队列尾的数据
    }

    //判断数组是否为空
    public boolean isEmpty() {
   
        return front == rear;
    }

    //判断数组是否已满
    public boolean isFull() {
   
        return rear == maxSize - 1;
    }

    //添加数据
    public void addQueue(int n) {
   
        if (! isFull()) {
   
            rear++;
            arr[rear] = n;
        } else {
   
            System.out.println("队列已满不能添加数据");
        }
    }

    //获取队列数据
    public int getQueue() {
   
        if (! isEmpty()) {
   
            front++; //因为front代表队列头的前一个数据,所以需要++
            return arr[front];
        } else {
   
            throw new RuntimeException("队列为空 不能取出数据");
        }
    }

    //显示队列的所有数据
    public void showQueue() {
   
        if (! isEmpty()) {
   
            for (int i = 0; i < arr.length; i++) {
   
                System.out.printf("arr[%d]=%d\n", i, arr[i]);
            }
        } else {
   
            System.out.println("队列为空,无法遍历数据");
        }
    }

    //显示队列的头数据
    public int headQueue() {
   
        if (! isEmpty()) {
   
            return arr[front+1];
        } else {
   
            throw new RuntimeException("队列为空,无法取出");
        }
    }
}

数组模拟环形队列

在上一个ArrayQueueDemo的基础上优化程序,达到复用的效果

思路如下:

  1. front变量的含义做一个调整:front就指向队列的第一个元素,也就是说arr[front]就是队列的第一个元素
  2. front的初始值为0
  3. rear变量的含义做一个调整:rear指向队列的最后一个元素的后一个位置,因为希望空出一个空间作为约定
  4. rear的初始值为0
  5. 当队列满时,条件是:(rear+1)%maxSize = front
  6. 当队列为空的条件,rear==front
  7. 当我们这样分析,队列中有效的数据个数(rear+maxSize-front)%maxSize
  8. 在上一个demo中修改得到一个环形队列

Java数据结构_第4张图片

代码实现

package com.yhs.queue;

import java.util.Scanner;

@SuppressWarnings("all")
public class CircleArrayQueue {
   
    public static void main(String[] args) {
   
        //测试
        //这里设置为4,其队列有效数据最大为3
        //约定的位置是动态变化的
        CircleArray circleArray = new CircleArray(4);
        char key = ' ';
        Scanner scanner = new Scanner(System.in);
        boolean loop = true;
        //输出一个菜单
        while (loop) {
   
            System.out.println("s(show): 显示队列");
            System.out.println("e(exit): 退出程序");
            System.out.println("a(add): 添加数据到队列");
            System.out.println("g(get): 从队列取出数据");
            System.out.println("h(head): 查看队列头的数据");
            System.out.print("请输入你的选择: ");
            key = scanner.next().charAt(0);
            switch (key) {
   
                case 's':
                    circleArray.showQueue();
                    break;
                case 'a':
                    System.out.print("请输入添加的数据: ");
                    int value = scanner.nextInt();
                    circleArray.addQueue(value);
                    break;
                case 'g':
                    try {
   
                        int res = circleArray.getQueue();
                        System.out.printf("取出的数据是%d\n", res);
                    } catch (Exception e) {
   
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h':
                    try {
   
                        int res = circleArray.headQueue();
                        System.out.printf("取出的头数据=%d\n", res);
                    } catch (Exception e) {
   
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e':
                    scanner.close();
                    loop = false;
                    break;
                default:
                    break;
            }
        }
        System.out.println("程序退出");
    }
}

class CircleArray {
   
    private int maxSize; //数组最大容量
    //front 变量的含义作调整:指向队列的第一个元素,也就是arr[front] = arr[0];
    //front 的初始值 = 0
    private int front;
    //rear 变量的含义作调整: 指向队列的最后一个元素的后一个位置
    //rear 的初始值 = = 0
    private int rear; //队列尾
    private int[] arr;

    //构造器
    public CircleArray(int arrMaxSize) {
   
        maxSize = arrMaxSize;
        arr = new int[maxSize];
    }

    //判断是否为空
    public boolean isEmpty() {
   
        return front == rear;
    }

    //判断是否已满
    public boolean isFull() {
   
        return (rear + 1) % maxSize == front;
    }

    //添加数据到队列
    public void addQueue(int n) {
   
        // 判断队列是否满
        if (!isFull()) {
   
            arr[rear] = n;
            rear = (rear + 1) % maxSize;
        } else {
   
            System.out.println("队列已满,不能加入...");
        }
    }

    //获取队列中的数据
    public int getQueue() {
   
        if (!isEmpty()) {
   
            //front指向队列中的第一个元素
            //1. 先将front存入一个零时变量
            //2. 将front 后移动,考虑取模
            //3. 将临时保存的变量返回
            int value = arr[front];
            front = (front + 1) % maxSize;
            return value;
        } else {
   
            throw new RuntimeException("队列为空,无法取出");
        }
    }

    //显示队列中的数据
    public void showQueue() {
   
        if (!isEmpty()) {
   
            for (int i = front; i <  front + dataNum(); i++) {
   
                System.out.printf("arr[%d]=%d\n", i % maxSize, arr[i % maxSize]);
            }
        } else {
   
            System.out.println("队列为空,无法显示...");
        }
    }

    //求出当前队列有效数据的数量
    public int dataNum() {
   
        return (rear + maxSize - front) % maxSize;
    }

    public int headQueue() {
   
        //判断
        if (!isEmpty()) {
   
            return arr[front];
        } else {
   
            throw new RuntimeException("队列为空,没有数据...");
        }
    }
}

单链表

链表(Linked List)链表是有序的列表,是链式存储结构

Java数据结构_第5张图片

链表 增查 实现思路

【添加方式一】

Java数据结构_第6张图片

按照编号顺序添加

【添加方式二】

Java数据结构_第7张图片

单链表节点删除

Java数据结构_第8张图片

package com.yhs.linkedlist;

public class SingleLinkedListDemo {
   
    public static void main(String[] args) {
   
        //测试
        //创建节点
        HeroNode h1 = new HeroNode(1, "詹姆斯", "小皇帝");
        HeroNode h2 = new HeroNode(2, "奥尼尔", "大鲨鱼");
        HeroNode h3 = new HeroNode(3, "邓肯", "石佛");
        HeroNode h4 = new HeroNode(4, "库里", "小学生");

        //创建一个链表
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        //方式一:加入
//        singleLinkedList.addHeroNode(h1);
//        singleLinkedList.addHeroNode(h4);
//        singleLinkedList.addHeroNode(h2);
//        singleLinkedList.addHeroNode(h3);

        //方式二:加入按照编号的顺序
        singleLinkedList.addByOrder(h1);
        singleLinkedList.addByOrder(h4);
        singleLinkedList.addByOrder(h2);
        singleLinkedList.addByOrder(h3);

        //显示
        singleLinkedList.list();

        //测试修改节点的代码
        HeroNode newHeroNode = new HeroNode(2, "科比", "小飞侠");
        singleLinkedList.update(newHeroNode);
        System.out.println("=========修改后=========");
        singleLinkedList.list();

        //测试删除节点
        singleLinkedList.delete(1);
        singleLinkedList.delete(2);
        singleLinkedList.delete(3);
        singleLinkedList.delete(4);
        System.out.println("=============删除后===========");
        singleLinkedList.list();

    }
}

//定义一个SingleLinkedList 管理我们的英雄
class SingleLinkedList {
   
    //初始化一个头节点,头节点不存放数据
    private HeroNode headN = new HeroNode(0, "", "");

    //【方式一】添加节点到单项链表,不考虑编号顺序时
    //1. 找到当前链表的最后的节点
    //2. 将最后的节点的next 指向新的节点
    public void addHeroNode(HeroNode heroNode) {
   
        //因为head节点不能动,因此我们需要一个辅助的变量 temp
        HeroNode temp = headN;
        //遍历链表,找到最后
        while (true) {
   
            if (temp.next == null) {
   
                break;
            }
            //如果没有找到最后,就将temp后移
            temp = temp.next;
        }
        //当退出while循环时,temp就指向新的节点
        temp.next = heroNode;
    }

    //【方式二】添加节点时,根据排名将英雄插入到指定位置
    //(如果有这个排名,则添加失败,并给出提示)
    public void addByOrder(HeroNode heroNode) {
   
        //因为头节点不能动,因此我们仍然通过一个辅助指针(变量)来帮助找到添加的位置
        HeroNode temp = headN;
        boolean flag = false; //标志添加的编号是否存在,默认为false
        while (true) {
   
            if (temp.next == null) {
    //说明temp已经在链表的最后
                break;
            }
            if (temp.next.no > heroNode.no) {
    //位置找到就在temp后面插入
                break;
            } else if (temp.next.no == heroNode.no) {
    //说明希望添加的heroNode编号已存在
                flag = true;
                break;
            }
            temp = temp.next;
        }
        //判断flag的值
        if (flag) {
    //编号已经存在,不能添加
            System.out.printf("准备插入的英雄编号 %d 已经存在,不能添加\n", heroNode.no);
        } else {
   
            //插入到链表,temp的后面
            heroNode.next = temp.next;
            temp.next = heroNode;
        }
    }

    //修改节点的信息,根据no编号来修改,即no编号不能改变
    //1. 根据 newHeroNode 的 no 来进行修改
    public void update(HeroNode newHeroNode) {
   
        //判断是否为空
        if (headN.next == null) {
   
            System.out.println("链表为空...");
            return;
        }
        //找到需要修改的节点
        //定义一个辅助指针
        HeroNode temp = headN.next;
        boolean loop = false; //表示是否找到该节点
        while (true) {
   
            if (temp.no == newHeroNode.no) {
   
                loop = true;
                break;
            }
            temp = temp.next;
            if (temp == null) {
   
                return;
            }
        }
        if (loop) {
   
            temp.name = newHeroNode.name;
            temp.nickName = newHeroNode.nickName;
        } else {
   
            System.out.printf("没有找到编号= %d 的节点,不能修改", newHeroNode.no);
        }
    }

    //删除节点
    //1. head 不能动,因此我们需要一个辅助指针找到删除节点的前一个节点
    //2. 说明我们比较时,时temp.next.no 和 需要删除的节点no比较
    public void delete(int no) {
   
        HeroNode temp = headN;
        boolean loop = false; //标志是否找到待删除的节点
        while (true) {
   
            if (temp.next == null) {
   
                break;
            }
            if (temp.next.no == no) {
   
                loop = true;
                break;
            }
            temp = temp.next;
        }
        //判断是否找到该节点
        if (loop) {
    //找到
            //删除该节点
            temp.next = temp.next.next;
        } else {
   
            System.out.printf("删除失败...该节点 %d不存在", no);
        }
    }


    //显示链表
    public void list() {
   
        //先判断链表是否为空
        if (headN.next == null) {
   
            System.out.println("链表为空");
            return;
        }
        //因为头节点不能动,因此我们需要定义一个辅助变量来遍历
        HeroNode temp = headN.next;
        while (true) {
   
            //判断是否到链表最后
            if (temp == null) {
   
                break;
            }
            //输出节点信息
            System.out.println(temp);
            //将temp后移
            temp = temp.next;

//            第二种写法
//        while (true) {
   
//            System.out.println(temp);
//            temp = temp.next;
//            if (temp == null) {
   
//                break;
//            }
//        }
        }
    }

}


class HeroNode {
   
    public int no;
    public String name;
    public String nickName;
    public HeroNode next;

    //构造器
    public HeroNode(int no, String name, String nickName) {
   
        this.no = no;
        this.name = name;
        this.nickName = nickName;
    }

    //为了方便显示,重写toString
    @Override
    public String toString() {
   
        return "HeroNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", nickName='" + nickName + '\'' +
                '}';
    }
}

单链表面试题

获取单链表有效节点个数
public static int getLength(HeroNode headN) {
   
    if (headN.next == null) {
   
        return 0;
    }
    int length = 0;
    HeroNode temp = headN.next;
    while (temp != null) {
   
        length++;
        temp = temp.next;
    }
    return length;
}
查找单链表倒数第k个节点
//1. 编写一个方法,接收head节点,同时接收一个index
//2. index 表示倒数第index个节点
//3. 先把链表从头到尾遍历,得到链表的总长度
//4. 得到size后,我们从链表的第一个开始遍历(size - index)个,就可以得到
//5. 如果找到了,则返回该节点,否则返回null
public HeroNode getKNode(HeroNode headN, int index) {
   
    if (headN.next == null) {
   
        return null;
    }
    int size = 0;
    HeroNode temp = headN.next;
    while (temp != null) {
   
        size++;
        temp = temp.next;
    }
    //第二次遍历 size-index 位置,就是倒数的第k个节点
    //先做一个index的校验
    if (index <= 0 || index > size) {
   
        return null;
    }
    temp = headN.next;
    //for循环 定位到倒数的index
    for (int i = 0; i < size - index; i++) {
   
        temp = temp.next;
    }
    return temp;
}
单链表反转

方式一

Java数据结构_第9张图片

//将单链表反转
public static void reverseList(HeroNode headN) {
   
    //如果当前链表为空,或者只有一个节点,无序反转,直接返回
    if (headN.next == null || headN.next.next == null) {
   
        return;
    }
    //定义一个辅助的指针,帮助我们遍历原来的链表
    HeroNode cur = headN.next;
    HeroNode next = null; //指向当前节点[cur]的下一个节点
    HeroNode reverseHead = new HeroNode(0,"", "");
    //并从头到尾遍历原来的链表,每遍历一个节点,就将其取出,并放在新的链表reverseHead 的最前端
    while (cur != null) {
   
        next = cur.next; //先暂时保存当前节点的下一个节点,因为后面需要使用
        cur.next = reverseHead.next;
        reverseHead.next = cur; //将cur连接到新的链表上
        cur = next; //让temp后移
    }
    //将head.next 指向 reverseHead.next 实现链表反转
    headN.next = reverseHead.next;
}

方式二

//将单链表反转 -- 双指针解法
    public void reverseList(HeroNode headN) {
   
        //如果当前链表为空,或者只有一个节点,无序反转,直接返回
        if (headN.next == null || headN.next.next == null) {
   
            return;
        }
        //定义一个辅助的指针,帮助我们遍历原来的链表
        HeroNode cur = headN.next;
        HeroNode pre = null;
        HeroNode temp = null; //辅助指针
        while (cur != null) {
   
            temp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = temp;
        }
        headN.next = pre;
    }
从尾到头打印单链表

测试Stack(栈)的使用

public class TestStock {
   
    public static void main(String[] args) {
   
        Stack<String> stack = new Stack<>();
        //入栈
        stack.add("jack");
        stack.add("tom");
        stack.add("smith");
        //出栈
        while (stack.size() > 0) {
   
            System.out.println(stack.pop());
        }
    }
}

Java数据结构_第10张图片

//倒序打印链表
//可以利用栈这个数据结构,将各个节点压入到栈中,然后利用栈的先进后出的特点,实现逆序打印效果
public void reversePrint(HeroNode headN) {
   
    if (headN.next == null) {
   
        return;
    }
    //创建一个栈,将各个节点压入栈中
    Stack<HeroNode> stack = new Stack<>();
    HeroNode cur = headN.next;
    //将链表的所有节点压入栈
    while (cur != null) {
   
        stack.push(cur);
        cur = cur.next;
    }
    //将栈中的节点进行打印 pop出栈
    while (stack.size() > 0) {
   
        System.out.println(stack.pop()); //stack的特点:先进后出
    }
}

双向链表

使用单项链表的缺点分析

  1. 单项链表,查找的方向只能是一个方向,二双向链表可以向前或者向后查找
  2. 单项链表的不能自我删除,需要靠辅助节点,而双向链表,则可以自我删除,所以之前我们单项链表删除节点时,总是找到temp(待删除节点的前一个节点)

双向链表CRUD分析图解

Java数据结构_第11张图片

代码实现

package com.yhs.linkedlist;

public class DoubleLinkedListDemo {
   
    public static void main(String[] args) {
   
        //测试
        //创建节点
        System.out.println("~~~~~~~~双向链表测试~~~~~");
        HeroNode2 h1 = new HeroNode2(1, "詹姆斯", "小皇帝");
        HeroNode2 h2 = new HeroNode2(2, "奥尼尔", "大鲨鱼");
        HeroNode2 h3 = new HeroNode2(3, "邓肯"

你可能感兴趣的:(java,数据结构,ide)