Java 基础09-数组和算法

282 阅读13分钟

数组和算法

1. 数组

1.1 为什么要使用数组

在开发中会出现大量重复的,并且是同一个类型的数据,需要同时时候,如果按照一个一个的变量定义,会导致代码出现以下一些问题:
	1、代码过于臃肿
	2、代码阅读性极差
	3、代码维护性极差

1.2 Java 中定义数组的格式

变量的定义格式:
    数据类型 变量名 = 初始化数据;

数组的定义格式:
    数据类型[] 数组名 = new 数据类型[容量];

赋值号左侧:
    数据类型:
    	确定当前数组中能够保存数据类型是什么,要求当前数组中有且只能保存指定的数据类型,严格执行数据类型一致化。
    
    []:
    	1、确定当前创建的是一个数组类型;
    	2、确定数组名是一个"引用数据类型",引用数据的变量里面保存的是另一个数据空间的地址。
            
	数组名:
		1、操作当前数组使用的名字;
		2、数组名是一个引用数据类型变量。
            
            
赋值号右侧:
	new:
		创建数组空间的关键字。
            
	数据类型:
		前后一致,保证数据类型一致化,要求创建的数据类型是指定的数据类型。
            
	[容量]:
		确定当前数组中数据容量是多少,而且创建之后,不可以改变。
            
数组的下标:
	数组的有效下标是从 0 开始到 数组的容量 - 1。
	如果数组的容量是 10,有效小标的范围就是 0 ~ 9。

使用格式:
	数组名[有效下标];
	arr[0] = 10;
	System.out.println(arr[0]);

1.3 数组的内存分析图

栈内存,存储的是值
    
数据存储在内存中

内存是分区域的,目前代码中会涉及到"栈区""堆区"

0x8848 这是内存地址。
认为是**省**市**区**路**号
    
数组下标 arr[0] arr[5]
认为是需要寻找的房间号 1001A 1005A

1.4 数组和循环不得不说的秘密

对于数组的 CRUD 操作都是依赖循环完成的,而且大部分使用的循环都是 for 循环。
    
因为 for 循环可以通过第一行的循环语句得知当前循环的大概次数,这个特征非常适用于数组。
public class Demo {
    
    public static void main(String[] args) {
        
        // 定义一个数组 int 类型,容量为 10
        int[] arr = new int[10];
        
        /*
        arr.length 是获取数组中的属性,数组的容量。
        arr.length 获取的结果就是 10
        */
        for(int i = 10; i < arr.length; i++) {
            arr[i] = i + 1;
        }
        
        for(int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}

1.5 数组作为方法的参数

// main方法就是一个使用数组作为形式参数列表的方法
// String[] args 就是一个数组作为方法参数的格式
// 数据类型[] 形式参数的名字
public static void main(String[] args) {
    
}


public class Demo {
    
    public static void main(String[] args) {
        
        // 定义一个int类型数组,容量为10
        int[] array = new int[10];

        /*
         该方法需要的参数是一个数组类型
         把数组名作为方法的参数传入!!!
        */
        assignIntArray(array);

        printIntArray(array);
    }
    
    /*
    需求:
        完成一个方法,给予int类型数组进行赋值操作
        方法名:
            assignIntArray
        形式参数列表:
            需要一个int类型数组,格式 int[] arr
        返回值类型:
            void 这里目前不考虑返回值类型

        public static void assignIntArray(int[] arr)
    */
    /**
     * 完成一个方法,给予int类型数组进行赋值操作
     * @param arr int类型的数组
     */
    public static void assignIntArray(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            arr[i] = i + 1;
        }
    }

    /*
    需求:
        完成一个方法,展示int类型数组
        方法名:
            printIntArray
        形式参数列表:
            需要展示的int类型数组,格式 int[] arr
        返回值类型:
            void 这里目前不考虑返回值类型,后期会考虑!!!boolean int

        public static void printIntArray(int[] arr);
    */
    /**
     * 展示一个int类型数组
     * @param arr 需要的int类型数组
     */
    public static void printIntArray(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}

2.练习

2.1 找出指定 int 类型数组中【最大值下标】和【最小值下标】位置

public class Demo {
    
    public static void main(String[] args) {
        
        int[] array = {1, 3, 5, 17, 9, 2, 4, 6, 17, 10};
        int index = maxIndexInArray(array);
        
        System.out.println(index);
    }

    /*
    定义一个方法,可以找出指定 int 类型数组中最大值下标位置

    方法分析:
        方法名:
            maxIndexInArray
        形式参数列表:
            这里需要一个 int 类型的数组 int[] array
        返回值类型:
            这里希望得到的是最大值下标,所有返回值类型是下标范围,就是 int 类型

        public static int maxIndexInArray(int[] array)
    */

    /**
     * 找出指定数组中最大值所在下标位置
     * @param array 指定的 int 类型数组
     * @return 返回最大值所在下标位置
     */
    public static int maxIndexInArray(int[] array) {
        
        // 1、假设下标为 0 的数据时最大值
        int maxIndex = 0;

        // 2、利用循环进行两两比较,并且数据比较从 1 开始
        for (int i = 1; i < array.length; i++) {
            // 3、判断下标为 maxIndex 元素如果小于下标为 i 的元素,保存下标 i 的值到 maxIndex
            if (array[maxIndex] < array[i]) {
                maxIndex = i;
            }
        }

        return maxIndex;
    }
}
/*
定义一个方法,可以找出指定 int 类型数组中最小值下标位置
方法分析:
    方法名:
        minIndexInArray
    形式参数列表:
        这里需要一个 int 类型的数组 int[] array
    返回值类型:
        这里希望得到的是最小值下标,所有返回值类型是下标范围,就是 int 类型
    public static int minIndexInArray(int[] arra
*/

/**
 * 找出指定数组中最小下标的元素
 * @param array 指定的 int 类型数组
 * @return 当前数组中最小值的下标位置
 */
public static int minIndexInArray(int[] array) {
    
    int minIndex = 0;
    for (int i = 1; i < array.length; i++) {
        if (array[minIndex] > array[i]) {
            minIndex = i;
        }
    }
    
    return minIndex;
}

2.2 找出指定 int 类型数据所在的【下标】位置

/*
定义一个方法,在指定 int 类型数组中,找出指定 int 类型数据所在的下标位置
找到返回值下标值: 0 ~ arr.length - 1
找不到返回 -1
方法分析:
    方法名:
        indexOf
    形式参数列表:
        第一个: 需要一个 int类型的数据 int[] array
        第二个: 确定需要查询的数据, int    int find
    返回值类型:
            int 类型,找到返回值大于等于 0,没有找到返回-1
    public static int indexOf(int[] array, int find)
*/

/**
 * 找出指定数据在指定数组中下标位置,找到返回值大于等 0,没有找到返回 -1
 * @param array 查询数据的数组 int 类型数组
 * @param find 查询的指定数据 in t类型数据
 * @return 找到返回值大于等 0,没有找到返回 -1
 */
public static int indexOf(int[] array, int find) {
    
    // 1、假设找不到数据
    int index = -1;

    // 2、利用循环,两两比较,找出指定数据在数组中下标位置,并且保存到 index 变量中
    for (int i = 0; i < array.length; i++) {
        // 3、下标为 i 的元素就是指定 find 数据,你们保存 下标 i 到 index 变量中
        if (array[i] == find) {
            index = i;
            // 4、如果找到数据,终止循环!!!break;
            break;
        }
    }

    return index;
}

2.3 找出所有指定数据的下标位置

import java.util.Arrays;

public class FindAllInArray {
    
    public static void main(String[] args) {
        
        int[] arr = {1, 3, 5, 7, 9, 1, 3, 5, 7, 9};
        int[] indexes = new int[arr.length];

        int count = findAllIndexes(arr, indexes, 5);
        System.out.println(count);

        for (int i = 0; i < count; i++) {
            System.out.println(indexes[i]);
        }
    }

    /*
    在一个数组中,找出所有指定数据的下标位置 【难】
    方法分析:
        方法名:
            findAllIndexes 找出所有指定元素的下标位置
        形式参数列表:
            1. 哪一个数组中进行查询操作!!! int[] arr
            2. 要查询的数据 int find
            3. 需要另外的一个数组,保存找到的下标位置
                a) 该数组是什么是就类型??? int类型数组
                b) 该数组的容量应该是什么???
                    和需要查询的目标数组容量是一致的!!!
        返回值类型;
            不考虑使用数组作为返回值,这里存在一定的隐患】
            boolean: 运行成功返回true,运行失败返回false
            int: ???
                返回找到的数据有多少个

        public static int findAllIndexes(int[] arr, int[] indexes, int find)
    */

    /**
     * 找出数组中指定元素 find在目标数组 arr的下标位置,并且保存到 indexes 数组中
     * 返回值是找到的元素个数,没有找到,返回 0
     * @param arr 查询数据目标数组,int类型
     * @param indexes 保存找到数据下标位置的数组,int类型
     * @param find 需要查询的数据,int类型
     * @return 返回值找到的元素个数,没有找到,返回 0
     */
    public static int findAllIndexes(int[] arr, int[] indexes, int find) {
        
        // 1. 参数合法性判断
        if (null == arr || null == indexes || arr.length == 0
                || indexes.length == 0 || indexes.length < arr.length) {
            System.out.println("Input parameter is invalid!");
           
            // 返回 0。结束方法,表示没有找到
            return 0;
        }

        // 2. 定义一个变量,计数
        int count = 0;

        // 3. 使用 for循环,遍历目标数组 arr,使用 if判断,找到目标元素
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == find) {
                /*
                a. 计数 count++
                b. 把找到的下标位置放到 indexes数组中
                第一次找到:
                    需要存放到下标为 0的位置,count++ count自增之前是 0
                第二次找到:
                    需要存放到下标为 1的位置,count++ count自增之前是 1

                indexes是存放下标位置的数组,count是计数有多少个目标数据
                i是找到的下标位置
                count同时可以表示当前 indexes数组中的有效元素个数
                 */
                indexes[count++] = i;
            }
        }

        return count;
    }
}

2.4 替换指定元素

import java.util.Arrays;

public class ArrayReplace {
    
    public static void main(String[] args) {
        
        int[] array = {1, 2, 3, 4, 5, 0, 0, 0, 0, 0};

        boolean ret = replace(array, 10);
        System.out.println(ret);
        System.out.println(Arrays.toString(array));
    }

    /*
    完成一个方法,替换掉数组中所有元素之为0的元素,替换为指定元素
    方法分析:
        方法名:
            replace
        形式参数列表:
            需要替换数据的int类型数据
            需要指定的元素 int类型
            (int[] array, int newNumber)
        返回值类型:
            不推荐使用void,使用void作为返回值的方法,是一个黑盒方法!!!
            给予当前方法一个状态的监控!!!
            boolean 方法运行成功返回true,失败返回一个false
            这玩意能失败???
                1. 如果数组的容量为0??? 会失败!!!
                2. 数组名是一个引用数据类型,其中保存的内存地址不能为 null 会失败!!!

        public static boolean replace(int[] array, int newNumber)
    */

    /**
     * 替换指定数据中元素为 0的值,替换为 newNumber
     * @param array int类型数组
     * @param newNumber 替换的int类型数组
     * @return 方法运行成功返回 true,方法运行失败,返回 false
     */
    public static boolean replace(int[] array, int newNumber) {
        
        // 1. 参数合法性判断!!!
        if (null == array || array.length == 0) {
            System.out.println("输入参数不合法!!!");
            
            // 输入参数不合法,返回 false 告知调用者,方法执行失败!!!
            return false;
        }

        for (int i = 0; i < array.length; i++) {
            if (0 == array[i]) {
                array[i] = newNumber;
            }
        }

        return true;
    }
}

2.4 删除指定下标元素

import java.util.Arrays;

public class ArrayRemove {
    
    public static void main(String[] args) {
        
        int[] array = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19};

        remove(array, 0);
        System.out.println(Arrays.toString(array));
    }

    /*
    完成一个方法,删除指定下标的元素,要求从删除位置开始,之后的元素整体前移。【难】
    要求源数据数组是
        int[] array = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19};
        删除之后,需要在数组的末尾补0,0是无效元素
    方法分析:
        方法名:
            remove / delete
        形式参数列表:
            1. 删除数据的目标数组 int[] arr
            2. 指定删除数据的下标位置 int index
        返回值类型:
            boolean 删除成功返回true,失败返回false
            什么情况下会失败:
                a) 数组容量为0
                b) 数组中保存的地址为 null
                c) 给予的删除下标是一个非法下标
        public static boolean remove(int[] arr, int index)
    */

    /**
     * 在指定数组中,删除指定下标 index上的元素。
     * @param arr 指定的 int类型数组
     * @param index 指定的删除数据的下标,但是不能超出数组的有效下标范围 0 ~ arr.length - 1
     * @return 删除操作成功返回 true,失败返回 false
     */
    public static boolean remove(int[] arr, int index) {
        
        // 1. 参数合法性判断
        if (null == arr || arr.length == 0 || index < 0 || index > arr.length -1 ) {
            System.out.println("Input parameter is invalid!");
            
            return false;
        }

        /*
         2. 使用 for循环完成操作
         这里使用 arr[i] = arr[i + 1];
        */
        for (int i = index; i < arr.length - 1; i++) {
            arr[i] = arr[i + 1];
            /*
            index = 5; arr.length = 10;
            arr[5] = arr[6]; i++ == 6
            arr[6] = arr[7]; i++ == 7
            arr[7] = arr[8]; i++ == 8
            arr[8] = arr[9]; i++ == 9
            arr[9] = arr[10]; ArrayIndexOutOfBoundsException
             */
        }

        arr[arr.length - 1] = 0;

        return true;
    }
}

2.5 添加元素到指定下标

import java.util.Arrays;

public class ArrayInsert {
    
    public static void main(String[] args) {
        
        int[] array = {1, 3, 5, 7, 9, 11, 13, 15, 17, 0};

        add(array, 20, 30);

        System.out.println(Arrays.toString(array));
    }

    /*
    完成一个方法,添加指定元素到指定下标位置,要求从指定下标位置之后的元素,整体向后移动。【难】
    要求源数据数组是
        int[] array = {1, 3, 5, 7, 9, 11, 13, 15, 17, 0};
        0是无效元素,表示目前数组存在一个空位置
    方法分析:
        方法名:
            add
        形式参数列表:
            1. 数组 int[] arr
            2. 指定下标位置 int index
            3. 添加的数据  int number
        返回值类型:
            boolean 成功返回true,失败返回false
            什么情况下会失败:
                a) 数组容量为0
                b) 数组中保存的地址为 null
                c) 给予的删除下标是一个非法下标

        public static boolean add(int[] arr, int index, int number)
    */

    /**
     * 在数组中指定位置,添加指定元素
     *
     * @param arr    指定的操作的数据,为 int类型
     * @param index  指定的下标位置,必须是在数组的有效下标范围以内 0 ~ 数组容量 - 1
     * @param number 添加的数据,为 int类型
     * @return 添加成功返回 true ,失败返回 false
     */
    public static boolean add(int[] arr, int index, int number) {
        
        // 1. 参数合法性判断
        if (null == arr || arr.length == 0 || index < 0 || index > arr.length - 1) {
            System.out.println("Input parameter is invalid!");
            return false;
        }

        // 2. 利用循环移动数组中的元素,从最后一位开始
        for (int i = arr.length - 1; i > index; i--) {
            arr[i] = arr[i - 1];
            /*
            index = 5; arr.length = 10;
            arr[9] = arr[8]; i-- == 8
            arr[8] = arr[7]; i-- == 7
            arr[7] = arr[6]; i-- == 6
            arr[6] = arr[5]; i-- == 5
             */
        }

        arr[index] = number;

        return true;
    }
}

3. 算法

3.1 选择排序算法

import java.util.Arrays;

public class ArraySort {
    
    public static void main(String[] args) {
        
        int[] arr = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10};

        selectSort(arr);

        System.out.println(Arrays.toString(arr));
    }
    /*
    完成一个选择排序算法
     */
    public static boolean selectSort(int[] arr) {
        // 1. 参数合法性判断
        if (null == arr || arr.length == 0) {
            System.out.println("Input parameter is invalid!");
            return false;
        }

        // 2. 外层循环控制需要进行多少次选择
        for (int i = 0; i < arr.length - 1; i++) {
            // 3. 使用一个变量,假设当前数组中极值
            int index = i;

            // 4. 找出极值下标位置
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[index] > arr[j]) {
                    index = j;
                }
            }

            // 5. 交换位置
            if (index != i) {
                int temp = arr[index];
                arr[index] = arr[i];
                arr[i] = temp;
            }
        }

        return true;
    }

3.2 冒泡排序算法

/*
冒泡排序
*/
public static void BubbleSort(int[] arr) {

	int length = arr.length;
	int temp;

	System.out.println("原始顺序: " + Arrays.toString(arr));

	//i表示第几趟排序
	for (int i = 1; i < length; i++) {

		//每次都从最后一个开始,知道第len-1趟排序
		for (int j = length - 1; j > i - 1; j--) {

			//如果后面的比前面的小,就像泡泡一样冒上去
			if (arr[j] < arr[j - 1]) {
				temp = arr[j];
				arr[j] = arr[j - 1];
				arr[j - 1] = temp;
			}
		}

		System.out.println("第" + i + "趟排序: " + Arrays.toString(arr));
	}
}

3.3 二分查找算法

//二分法查找
public class HalfSearch {
    public static void main(String[] args) {
        int[] arr = {1, 3, 5, 7, 9, 11, 13, 13, 13, 19};

        int i = halfSearch(arr, 13);
        System.out.println(i);
    }

    /**
     * 二分法查找
     * @param arr 经过排序的数组,默认为升序
     * @param find  需要查询的数据
     * @return 返回值为 int类型,找到数据的下标位置,如果没有找到返回 -1
     */
    public static int halfSearch(int[] arr, int find) {
        if (null == arr || arr.length == 0) {
            System.out.println("Input param is invalid");
            return -1;
        }

        int maxIndex = arr.length - 1;
        int minIndex = 0;
        int midIndex = (maxIndex + minIndex) / 2;

        while (minIndex <= maxIndex) {
            /*
             假如查询的数据时大于中间数据的,那么也就是说,查询的数据在中间数据右侧
             修改最小值下标
            */
            if (arr[midIndex] < find) {
                minIndex = midIndex + 1;
                /*
                 假如查询的数据是小于中间数据,证明当前查询的数据在中间数据的左侧
                 修改最大值下标
                */
            } else if (arr[midIndex] > find) {
                maxIndex = midIndex  - 1;
            } else {
                return midIndex;
            }

            midIndex = (maxIndex + minIndex) / 2;
        }
        return -1;
    }
}