小猿圈java之数组

基本数据结构中,数组是很重要的,这篇小猿圈加加对数组详解一席,具体使用,在学习过程中有困惑的朋友,可以看一下加加的这篇文章,看到就是赚到,让我们一起看看吧。

一、数组的基本使用

public class Array01 {

    /**

    * 数组:一组相同数据类型的集合!  在内存中开辟一连串的空间!

    *  和String一样都是  引用数据类型! 

    *  数据类型 [] 数组名称; 

    *  数组的下标=数组的长度-1

    */

    public static void main(String[] args) {

        // 01.声明数组 创建了一个火车厢

        int[] nums;

        // 02.分配空间 给火车厢创建座位

        nums = new int[5];

        // 03.赋值 旅客入座

        nums[0] = 50;

        // 04.使用 nums.length(获取数组的长度)

        for (int i = 0; i < nums.length; i++) {

            System.out.println("数组nums的第" + (i + 1) + "个位置的数据是:" + nums[i]);

        }

    }



    // 声明数组的同时给数组赋值

    @Test

    public void test01() {

        /**

        * 给你说 创建车厢的同时,告诉你里面有多少个座位

        *

        * int  [] nums;

        * nums={ 1, 2, 3, 4, 5 };  这种写法是错误的!

        */

        int[] nums = { 1, 2, 3, 4, 5 };

        // 找到下标为3的数据

        System.out.println(nums[3]);

    }

    @Test

    public void test02() {

        // int[] nums = new int[5]; 可以 常用的方式

        int[] nums = new int[] { 1, 2, 3, 4, 5 };

        // 找到下标为3的数据

        System.out.println(nums[3]);

    }

    /**

    * 计算5位学生的平均分

    */

    @Test

    public void test03() {

        // 01.创建一个长度为5的double类型的数组 保存学生成绩

        double[] scores = new double[5];

        // 02.循环给学生成绩赋值

        Scanner scanner = new Scanner(System.in);

        double sum = 0; // 保存总成绩

        for (int i = 0; i < scores.length; i++) {

            System.out.println("请输入第" + (i + 1) + "位同学的成绩");

            scores[i] = scanner.nextDouble();

            // 每个学生成绩需要加到sum中

            sum += scores[i];

        }

        System.out.println("学生的总成绩是:" + sum);

        System.out.println("学生的平均分是:" + (sum / scores.length));

    }

    /**

    * 有一个数列:8,4,2,1,23,344,12

    循环输出数列的值

    求数列中所有数值的和

    猜数游戏:从键盘中任意输入一个数据,判断数列中是否包含此数

    */

    @Test

    public void test04() {

        // 01.创建int类型数组

        int nums[] = { 8, 4, 2, 1, 23, 344, 12 };

        // 定义变量保存总和

        int sum = 0;

        // 02.循环输出数列的值

        for (int i = 0; i < nums.length; i++) {

            System.out.print(nums[i] + ",");

            sum += nums[i];

        }

        System.out.println("\n数组中数值的总和:" + sum);

        // 猜数游戏:从键盘中任意输入一个数据,判断数列中是否包含此数

        Scanner scanner = new Scanner(System.in);

        System.out.println("请输入一个数字:");

        int num = scanner.nextInt();

        // 定义标记 来记录是否中奖

        boolean flag = false;

        for (int i = 0; i < nums.length; i++) {

            if (num == nums[i]) {

                flag = true;

                break;

            }

        }

        if (flag) { // 判断标记

            System.out.println("恭喜您!中大奖!");

        } else {

            System.out.println("没有找到......");

        }

    }

    /**

    * 以表格的形式输出5笔购物金额及总金额

    */

    @Test

    public void test05() {

        double[] pays = new double[5];

        double sum = 0; // 总金额

        Scanner scanner = new Scanner(System.in);

        System.out.println("请输入本月的消费记录:");

        for (int i = 0; i < pays.length; i++) {

            System.out.println("请输入" + (i + 1) + "次的消费金额:");

            pays[i] = scanner.nextDouble(); // 给数组中每一个元素赋值

            // 求和

            sum += pays[i];

        }

        // 输出消费详情 遍历(从集合中取得数据)

        System.out.println("序号\t\t金额");

        for (int i = 0; i < pays.length; i++) {

            System.out.println((i + 1) + "\t\t" + pays[i]);

        }

        System.out.println("总金额:" + sum);

    }

    /**

    * Arrays  :数组的操作类

    */

    @Test

    public void test06() {

        double[] pays = new double[5];

        Scanner scanner = new Scanner(System.in);

        System.out.println("请输入本月的消费记录:");

        for (int i = 0; i < pays.length; i++) {

            System.out.println("请输入" + (i + 1) + "次的消费金额:");

            pays[i] = scanner.nextDouble(); // 给数组中每一个元素赋值

        }

        // 没有排序的遍历

        for (int i = 0; i < pays.length; i++) {

            System.out.println(pays[i]);

        }

        System.out.println("*************升序之后***************");

        Arrays.sort(pays);// 升序排列

        for (int i = 0; i < pays.length; i++) {

            System.out.println(pays[i]);

        }

    }

}

二、操作数组的工具类

/**

* 操作数组的工具类!

*/

public class Arrays02 {

    // equals(arr1, arr2) :比较两个数组的内容和长度 是否一致

    @Test

    public void testEquals() {

        int[] nums1 = { 10, 20, 30, 50 };

        int[] nums2 = nums1;

        int[] nums3 = { 10, 20, 30 };

        System.out.println("nums1与nums2比较:" + Arrays.equals(nums1, nums2));

        System.out.println("nums1==nums2比较:" + (nums1 == nums2));

    }

    // sort(arr):对数组中的元素进行升序的排列

    @Test

    public void testSort() {

        int[] nums = { 10, 50, 30, 20 };

        Arrays.sort(nums);

        for (int i = 0; i < nums.length; i++) {

            System.out.println(nums[i]);

        }

    }

    /**

    *  toString :把一个数组变成字符串

    *  [10, 50, 30, 20]  集合toString的结果!

    */

    @Test

    public void testToString() {

        int[] nums = { 10, 50, 30, 20 };

        System.out.println(Arrays.toString(nums));

    }

    /**

    * fill(arr,val):将arr数组中的所有元素都赋值成了val

    */

    @Test

    public void testFill() {

        int[] nums = { 10, 50, 30, 20 };

        System.out.println(Arrays.toString(nums));

        Arrays.fill(nums, 100);

        System.out.println(Arrays.toString(nums));

    }

    /**

    * copyOf(arr,length):将数组arr复制成一个长度为length的新数组!

    */

    @Test

    public void testCopyOf() {

        int[] nums = { 10, 50, 30, 20 };

        int[] nums1 = Arrays.copyOf(nums, 3);

        System.out.println(Arrays.toString(nums1));

    }

    /**

    * binarySearch(arr,val):查询val在arr数组中的下标!

    * 必须先升序排列!  Arrays.sort(arr)!!!!

    */

    @Test

    public void testBinarySearch() {

        int[] nums = { 10, 50, 30, 20 };

        Arrays.sort(nums); // 10 20 30 50

        System.out.println(Arrays.binarySearch(nums, 50));

    }

}

三、多重数组

public class DoubleArray04 {

    public static void main(String[] args) {

        int[] clazz = new int[3]; // 保存班级

        int[] students = new int[5]; // 保存学生

    }

    @Test

    public void test01() { // 声明的同时开辟空间

        int[][] nums = new int[3][5]; // 3个班级各5名学生

    }

    @Test

    public void test02() { // 先声明 再 开辟空间

        int[][] nums;

        nums = new int[3][5]; // 3个班级各5名学生

    }

    @Test

    public void test03() { // 声明 开辟空间的同时赋值

        int[][] nums = { { 1, 2, 3, 4, 5 }, { 1, 2, 3, 4, 5 },

                { 1, 2, 3, 4, 5 } };

        System.out.println(nums.length);// 3个班级各5名学生

    }

    @Test

    public void test04() {

        int[][] nums = new int[3][5]; // 3个班级各5名学生

        // 第二个班级的第三个学生

        nums[1][2] = 50;

    }

    @Test

    public void test05() {

        int[][] nums = { { 1, 2, 3 }, { 10, 20, 30 }, { 100, 200, 300 } };

        /**

        * nums.length  车厢数

        * nums[i].length 车厢中的座位数

        * 双重循环:

        *  外层循环执行一次,内存循环执行一遍!

        */

        for (int i = 0; i < nums.length; i++) {

            System.out.println("进入了第" + (i + 1) + "个车厢**********");

            if (i == 2) {

                break; // 跳出当前循环体

            }

            for (int j = 0; j < nums[i].length; j++) {

                if (j == 2) {

                    break; // 跳出当前循环体

                }

                System.out.println(nums[i][j]);

            }

        }

    }

    /**

    * 所有的引用数据类型如果没有实例化(开辟空间)! 不能使用!

    * 因为引用数据类型的默认值 是  null!

    */

    @Test

    public void test06() {

        int[][] nums = new int[5][];

        System.out.println(nums.length);

        nums[0] = new int[5]; // 开辟空间

        nums[1] = new int[6];

        nums[0][0] = 50; // 使用

        nums[0][1] = 60;

        nums[0][2] = 70;

        nums[0][3] = 80;

        System.out.println(nums[0].length);

        System.out.println(nums[1].length);

    }

}

四、二维数组

/**

    * 二维数组: 数组中的元素 又是一个数组!

    */

    @Test

    public void test06(){

        //01.创建二维数组

        int[][] nums=new int[3][3]; //int [][] nums2={{1,2,3},{4,5,6},{7,8,9}};       

        nums[0][0]=5;

        nums[0][1]=6;

        nums[0][2]=7;



        nums[1][0]=5;

        nums[1][1]=6;

        nums[1][2]=7;



        nums[2][0]=5;

        nums[2][1]=6;

        nums[2][2]=7;   

    }   



    @Test

    public void test07(){

        //01.创建二维数组

        int [][] nums={{1,2,3,4},{4,5,6},{7,8}};



        System.out.println(nums[0]);//{1,2,3}

        System.out.println(nums[0][1]);//2

        System.out.println("nums的长度:"+nums.length);

        System.out.println("第2个数组中下标是2的元素"+nums[1][2]);

    }



    /**

    * 循环打印出数组所有的元素

    */

    @Test

    public void test08(){

        //01.创建二维数组

        int [][] nums={{1,2,3,4},{4,5,6},{7,8}};

        for (int i = 0; i < nums.length; i++) {  //外层

            System.out.println("这是2维数组中的第"+(i+1)+"个数组");

            for (int j = 0; j < nums[i].length; j++) {//内层

                System.out.println("元素的值:"+nums[i][j]);

            }

        }     

    }

数组的详解具体就是上面这些,大家可以好好练习一下,针对数组一定要会变通,会写二维数组、用数组实现冒泡排序等等,一定要掌握,重中之重,小编认为这篇数组讲的还算详细、清晰,希望大家看后可以好好保存,也可以去小猿圈学习通过视频,一个免费的学习平台。

<think>好的,用户现在想了解链表,我需要先确定他们的知识水平和具体需求。他们之前问了关于Java的Hashtable和HashMap的使用,可能现在在学习数据结构,或者在准备面试。链表是基础的数据结构之一,所以需要详细但清晰的解释。 首先,我要明确链表的基本概念,包括节点结构,每个节点包含数据和指针。对比数组,强调链表的动态性和内存利用的优势。然后,区分单链表、双向链表和循环链表,说明各自的特点和适用场景。 接下来,用户可能关心链表的操作,比如插入、删除、查找,这些需要分步骤解释,最好用代码示例,特别是Java的实现,因为他们之前的问题是关于Java的。要确保代码简洁,并说明关键点,比如头结点的处理。 还要注意链表的优缺点,特别是与数组的对比。用户可能在实际应用中选择数据结构时需要权衡这些因素。比如,链表适合频繁插入删除,而数组适合随机访问。 此外,用户可能对链表在Java中的应用感兴趣,比如LinkedList类,可以简单提及,但主要焦点还是自定义链表的实现。可能还需要提到常见问题,如检测环、反转链表等,但根据用户的问题,可能暂时不需要深入,除非他们进一步提问。 需要检查是否有理解错误,比如用户是否混淆了链表和其他结构,或者需要更多实际例子。回答的结构要清晰,分点讲解,使用代码块和对比表格,便于理解。最后,确保语言口语化,避免术语堆砌,让用户容易跟随。</think>以下是关于链表的系统性讲解,包含核心概念、代码实现和应用场景: --- ### 一、链表基础概念 #### 1. 核心定义 - **数据结构**:由节点(Node)通过指针连接构成的线性序列 - **节点结构**: ```java class Node { T data; // 存储数据 Node next; // 指向下一个节点(单链表) Node prev; // 双向链表特有,指向前驱节点 } ``` #### 2. 与数组对比 | 特性 | 数组 | 链表 | |---------------|--------------------------|--------------------------| | **内存分配** | 连续内存块 | 非连续动态分配 | | **扩容成本** | 需要重新分配内存 | 只需修改指针 | | **访问速度** | $O(1)$ 随机访问 | $O(n)$ 顺序访问 | | **插入/删除** | $O(n)$ 需移动元素 | $O(1)$(已知节点位置) | --- ### 二、链表类型详解 #### 1. 单链表(Singly Linked List) - **结构特征**: - 每个节点包含数据和`next`指针 - 最后一个节点指向`null` - 典型操作示意图: ``` Head → [A|→] → [B|→] → [C|→] → null ``` - **Java实现关键代码**: ```java class SingleLinkedList<T> { Node head; // 头节点 class Node { T data; Node next; Node(T d) { data = d; } } // 头部插入新节点 public void addFirst(T data) { Node newNode = new Node(data); newNode.next = head; head = newNode; } } ``` #### 2. 双向链表(Doubly Linked List) - **结构优势**: - 支持双向遍历 - 删除操作更高效(无需遍历找前驱节点) - 内存占用多一个指针空间 - **操作示意图**: ``` null ← [⇌A⇌] ↔ [⇌B⇌] ↔ [⇌C⇌] → null ``` - **Java实现片段**: ```java class DoublyLinkedList<T> { Node head, tail; class Node { T data; Node prev, next; Node(T d) { data = d; } } // 尾部插入 public void addLast(T data) { Node newNode = new Node(data); if (tail == null) { // 空链表 head = tail = newNode; } else { tail.next = newNode; newNode.prev = tail; tail = newNode; } } } ``` #### 3. 循环链表(Circular Linked List) - **核心特征**: - 尾节点指向头节点形成闭环 - 适合环形缓冲区等场景 - 遍历时需要设置终止条件 --- ### 三、关键操作的时间复杂度 | 操作 | 时间复杂度 | 备注 | |-------------------|------------|------------------------------| | 访问第k个元素 | $O(n)$ | 必须从头遍历 | | 头部插入/删除 | $O(1)$ | 直接操作头指针 | | 尾部插入/删除 | $O(1)$ | 双向链表适用,单链表需$O(n)$ | | 指定位置插入 | $O(1)$ | 已知前驱节点时 | | 按值查找 | $O(n)$ | 需要遍历全部节点 | --- ### 四、实战应用场景 #### 1. 高频使用场景 - **内存管理系统**:内存块的动态分配 - **LRU缓存淘汰算法**:快速移动节点位置 - **浏览器历史记录**:前进/后退功能实现 - **多项式运算**:非零项的灵活存储 - **区块链结构**:通过哈希指针连接区块 #### 2. Java标准库实现 - `java.util.LinkedList`:实际是双向链表实现 ```java LinkedList<String> list = new LinkedList<>(); list.addFirst("A"); // 头部插入 list.removeLast(); // 尾部删除 ``` --- ### 五、手写链表常见考题 #### 1. 基础操作实现 ```java // 反转单链表(迭代法) Node reverseList(Node head) { Node prev = null; Node curr = head; while (curr != null) { Node nextTemp = curr.next; curr.next = prev; prev = curr; curr = nextTemp; } return prev; } ``` #### 2. 典型算法问题 - **检测环**(Floyd判算法): ```java boolean hasCycle(Node head) { Node slow = head, fast = head; while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; if (slow == fast) return true; } return false; } ``` - **合并两个有序链表**: ```java Node mergeTwoLists(Node l1, Node l2) { Node dummy = new Node(-1); Node curr = dummy; while (l1 != null && l2 != null) { if (l1.val <= l2.val) { curr.next = l1; l1 = l1.next; } else { curr.next = l2; l2 = l2.next; } curr = curr.next; } curr.next = (l1 != null) ? l1 : l2; return dummy.next; } ``` --- ### 六、链表 vs 数组选择策略 | **优先选择链表** | **优先选择数组** | |------------------------------|--------------------------------| | 频繁在头部/中部插入删除 | 需要快速随机访问元素 | | 数据总量不确定且变化频繁 | 数据规模已知且稳定 | | 内存碎片化问题需要避免 | 需要空间局部性优化缓存命中率 | --- ### 七、优化技巧总结 1. **哑节点(Dummy Node)**:简化头节点特殊处理 2. **快慢指针**:解决环检测、中点查找等问题 3. **递归法**:适用于链表反转等对称操作 4. **哈希辅助**:用于检测重复节点或交叉链表 通过理解这些核心要点,可以更高效地应对实际开发中的链表相关需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值