常见的排序算法

一、冒泡排序

将数组中的元素按照从小到大的顺序进行排序。

2185-80129

冒泡排序算法:

从左到右,逐个元素两两比较,如果前者比后者大,则交换这两个元素值;如果前者小于或等于后者,则不用交换;直至最后两个元素比较并交换;

8,21,5,-8,0,12,9

8,5,21,-8,0,12,9

8,5,-8,21,0,12,9

8,5,-8,0,21,12,9

8,5,-8,0,12,21,9

8,5,-8,0,12,9,21

这就完成了一趟排序。一趟过后,当前范围中的最大元素就被移动到当前范围最后的位置;该元素的最终位置就确定了,以后不会再变化。

第二趟,继续从左到右,逐个元素两两比较,前者如果大于后者,则交换;否则,不用交换。

直至倒数第二个和第三个比较完成。

8,5,-8,0,12,9,21

5,8,-8,0,12,9

5,-8,8,0,12,9

5,-8,0,8,12,9

5,-8,0,8,12,9

5,-8,0,8,9,12

第二趟完成后,倒数第二个元素就确定了最终位置。

。。。。。。

第n-1趟完成后,倒数第n-1个元素就确定了最终位置。

总结:

对于长度为n的数组,总共需要n-1趟;

每一趟要完成的任务:从下标0开始,两两比较,前者大就交换;直到下标为n-2;

for(int i=0;i<n-1;i++){

​ //i0时第一趟,i1时第二趟,i==2时第三趟…

for(int index=0;index<n-1-i;index++){

​ if(array[index]>array[index+1]){

​ //交换

​ }

}

}

//冒泡排序思路: 从前向后两两比较, 如果前面的数组元素大于后面的数组元素就进行交换
public class BubbleSort {
    public static void main(String[] args) {
        int[] array = {21, 8, 5, -8, 0, 12, 9};

        int n = array.length;
        //临时变量
        int t;
        //冒泡排序:外层循环控制趟数
        //数组有n个元素, 需要进行 n-1轮, 可以通过循环控制比较的轮次
        for (int i = 0; i < n - 1; i++) {
            //内层循环:从左到右,将大的值向右交换
            for (int index = 0; index < n - 1 - i; index++) {                 //判断第一个元素是否大于第二个元素,大于,交换两个元素的值,判断第二个元素是否大于第三个元素,大于就交换,以此类推...
                if (array[index] > array[index + 1]) {
                    //交换两个元素的值
                    t=array[index];
                    array[index]=array[index+1];
                    array[index+1]=t;
                }
            }
        }
        //输出结果
        showArray(array);
    }
    private static void showArray(int[] array) {
        if (array == null) {
            System.out.println("数组为null!");
            return;
        }
        System.out.print("数组中的所有元素值:");
        for (int i = 0; i < array.length; i++) {
            if (i > 0) System.out.print(",");
            System.out.print(array[i]);
        }
        System.out.println();
    }
}


冒泡排序算法:另一种实现

i表示趟数,从0开始,到达n-1;

每一趟,从右向左,下标从n-1开始直至1+i,两两比较,后者如果小于前者就交换,将小的元素向前移动。

public static void main(String[] args) {
        int[] array = {21, 8, 5, -8, 0, 12, 9};


        int t = 0;

        for (int i = 0; i < array.length - 1; i++) {
            //j>0或j>i都可以
            for (int j = array.length - 1; j > 0; j--) {
                if (array[j] < array[j - 1]) {

                    t = array[j];
                    array[j] = array[j - 1];
                    array[j - 1] = t;
                }
            }
        }
        showArray(array);
    }

    private static void showArray(int[] array) {
        if (array == null) {
            System.out.println("数组为null!");
            return;
        }
        System.out.print("数组中的所有元素值:");
        for (int i = 0; i < array.length; i++) {
            if (i > 0) System.out.print(",");
            System.out.print(array[i]);
        }
        System.out.println();
    }

时间复杂度:2n*2,空间复杂度1

二、选择排序

SelectionSort 选择排序:第一趟,从第一个元素开始一直遍历到末尾,找出最小元素,然后将该元素和第一个元素进行交换,也就确定了第一个元素的最终位置;第二趟,从第二个元素开始遍历到末尾,找出最小元素,然后和第二个元素交换,从而确定了第二个元素的最终位置;。。。。。。。。当第n-1趟后,也就确定了第n-1个元素的最终位置。排序结束。

public class SelectionSort {

    public static void main(String[] args) {
        int[] array = {21, 17, 1, -88, 0, 123, -9, 34, 28, 6};

        //
        selectionSort(array);
        showArray(array);
    }

    private static void showArray(int[] array) {
        if (array == null) {
            System.out.println("数组为null!");
            return;
        }
        System.out.print("数组中的所有元素值:");
        for (int i = 0; i < array.length; i++) {
            if (i > 0) System.out.print(",");
            System.out.print(array[i]);
        }
        System.out.println();
    }

    /**
     * 选择排序
     *
     * @param array
     */
    private static void selectionSort(int[] array) {
        if (array == null || array.length < 2) return;
        int temp = 0;
        //外层循环控制趟数
        for (int i = 0; i < array.length - 1; i++) {
            int index = i;//定义变量保存这一轮最小元素索引值
            //内层循环从i开始到尾遍历找出最小元素的下标
            for (int j = i + 1; j < array.length; j++) {
            //如果有元素比min标记的元素还小,则这个元素就是当前最小的
                if (array[j] < array[index]) {
                   index = j;//把当前最小元素索引值保存到index变量中
                }
            }
            //1,3,2
            if (index != i) {
                //和下标为i的元素(本趟开始的元素)进行交换
                temp = array[i];
                array[i] = array[index];
                array[index] = temp;
            }
        }
    }
}

三、二分查找(折半查找)

3.1二分查找

从数组中寻找指定的元素值,判断数组中是否存在该元素值。

二分查找算法思想:

1、将数组中的所有元素从小到大排序;

2、计算待查找序列的中间位置,将查找的值和中间位置元素进行比较;

如果中间位置值比查找的值大,查找范围变为之前的范围;

如果中间位置值比查找的值小,查找范围变为之后的范围;

如果中间位置值和查找的值相等,直接返回该下标;

循环第2步,直至范围中没有元素,返回-1。

{1,25,36,47,49,51,66,77,99}

要查找25:

1、start=0,end=8; middle=(0+8)/2=4;

2、array[4]对应的值49,大于25,查找范围start=0,end=3;

3、middle=(0+3)/2=1,array[1]=25,等于要查找的值,直接返回1.

要查找69:

1、start=0,end=8; middle=(0+8)/2=4;

2、array[4]对应的值49,小于要找的值69,修改范围start=5,end=8;

3、middle=(5+8)/2=6,array[6]对应的值66,修改范围start=7,end=8;

4、middle=(7+8)/2=7,array[7]对应的值77,修改范围start=7,end=6;

5、start已经超过end,返回-1。

public class BinarySearch {
    public static void main(String[] args) {

        int[] array = {1, 25, 36, 47, 51, 66, 77, 99};

        // 调用二分法查找,找到查找元素的索引
        int index = binarySearch(array, 51);
        System.out.println(index == -1 ? "没找到" : "所在的下标为:" + index);

        index = binarySearch(array, 61);
        System.out.println(index == -1 ? "没找到" : "所在的下标为:" + index);

        index = binarySearch(array, 1);
        System.out.println(index == -1 ? "没找到" : "所在的下标为:" + index);

        index = binarySearch(array, 66);
        System.out.println(index == -1 ? "没找到" : "所在的下标为:" + index);
    }

    /**
     * 使用二分法查找,从数组中查找特定的值
     *
     * @param array 需要查找的数组
     * @param key   需要查找的元素值
     * @return 如果返回值为正数,则证明找到;如果返回-1,则证明没找到。
     */
    private static int binarySearch(int[] array, int key) {
        if (array == null || array.length == 0) return -1;
        int start = 0, end = array.length - 1;
        int index = -1, middle;
        while (start <= end) {
            middle = (start + end) / 2;
            if (array[middle] == key) {
                index = middle;
                break;
            } else if (array[middle] < key) {
                start = middle + 1;
            } else {
                end = middle - 1;
            }
        }
        return index;
    }


}

3.2递归方法实现二分查找

public static void main(String[] args) {
    int[] array = {1, 25, 36, 47, 49, 51, 66, 77, 99};
    int index = binarySearch(array, 51, 0, array.length - 1);
    System.out.println(index == -1 ? "没找到!" : "所在下标为" + index);

    index = binarySearch(array, 61, 0, array.length - 1);
    System.out.println(index == -1 ? "没找到!" : "所在下标为" + index);

    index = binarySearch(array, 66, 0, array.length - 1);
    System.out.println(index == -1 ? "没找到!" : "所在下标为" + index);

    index = binarySearch(array, 1, 0, array.length - 1);
    System.out.println(index == -1 ? "没找到!" : "所在下标为" + index);

    index = binarySearch(array, 99, 0, array.length - 1);
    System.out.println(index == -1 ? "没找到!" : "所在下标为" + index);
}

public static int binarySearch(int[] array, int key, int start, int end) {
    if (array == null || array.length < 1) return -1;
    if (start > end || start >= array.length || end >= array.length || start < 0 || end < 0) return -1;
    //计算中间下标
    int middle = (start + end) / 2;
    if (array[middle] == key) {
        return middle;
    } else if (array[middle] > key) {
        return binarySearch(array, key, start, middle - 1);
    } else {
        return binarySearch(array, key, middle + 1, end);
    }
}

三、插入排序

/**
 *  插入排序
 */
public class Test04Insert {
    public static void main(String[] args) {
        int [] ints = { 54, 34, 78, 12, 9 , 20 , 65, 11 };
        //插入排序时, 把数组分为已排序与未排序两部分,
        //初始时已排序部分是0元素, 从1开始的元素是未排序的
        for( int i = 1;  i < ints.length; i++){     //从1位置开始遍历未排序的所有数组元素
            //1) 确定i位置的元素应该插入到前面已排序的位置x
            int tmp = ints[i];      //先把i位置元素保存到临时变量中
            int x = i;              //定义变量保存tmp数据在前面已排序数组部分的索引值
            //从后向前遍历已排序的数组元素, 如果数组元素比 tmp 更大,就向后移
            for( ; x > 0 && ints[x-1] > tmp; x--){
                ints[x] = ints[x-1];
            }

            //2) 把原来i位置元素保存到x位置上
            ints[x] = tmp;
        }

        for (int anInt : ints) {
            System.out.print(anInt + "  ");
        }
        System.out.println();

    }
}

四、补充知识

4.1 使用foreach循环结构遍历数组

语法:

for(变量类型 局部变量名 : 数组名){

}

每次迭代,都会将数组中的一个元素值赋值给局部变量,然后执行一次循环体。

需要确保数组不能是null值,否则会抛出NullPointerException异常。

【示例】文件名ForeachDemo.java

public class ForeachDemo {

    public static void main(String[] args) {
        int[] array = {23, 1, 24, 54, 4, 3, 10, -9, 55};

        //l变量可以是int,long等能够容纳数组元素值的类型
        //要确保array不能是null值
        //foreach循环无法在循环体中获得当前元素的下标
        for (long l : array) {
            System.out.println("l=" + l);
        }
    }
}

4.2 main方法的参数String[]的使用

开发者启动程序时,可以给程序传入一个参数值。这些传入的参数值就传递给了main方法。

如果是在命令行启动程序: java 类名 参数值1 参数值2 参数值3…

如果要传递的参数值为字符串且包含了空格,需要使用引号引起来。

【示例】启动程序时,传入学生的姓名,程序中使用这些姓名提示录入各个学生的身高。

文件名:MainParamDemo.java

import java.util.Scanner;

public class MainParamDemo {

    public static void main(String[] args) {
        if (args == null || args.length == 0) {
            System.out.println("没有传入学生姓名,程序直接结束!");
            return;
        }
        //用来存储身高值的数组
        float[] h = new float[args.length];
        //
        Scanner scanner = new Scanner(System.in);
        int index = 0;
        for (String name : args) {
            System.out.print("请输入" + name + "学生的身高:");
            h[index++] = scanner.nextFloat();
        }
        //计算平均身高
        float sum = 0;
        for (float h1 : h) {
            sum += h1;
        }
        System.out.println("平均身高为:" + sum / h.length + ".");
    }
}

4.3 变长参数

在定义方法时,使用变长参数的语法,使得在调用该方法时,可以传递任意数量的实参值。

【示例】定义方法,允许传入任意数量的学生姓名。

文件名:ParamVariable.java

public class ParamVariable {

    public static void main(String[] args) {
        showNames();
        showNames("张三");
        showNames("张三", "李四", "王五");
    }

    /**
     * 定义方法,允许传入任意数量的学生姓名。
     *
     * @param names
     */
    public static void showNames(String... names) {
        System.out.println("姓名的个数:" + names.length);
        //在方法体内部,变长参数可以被看作数组
        for (int i = 0; i < names.length; i++) {
            System.out.println(names[i]);
        }
        System.out.println("-----------------------");
    }
}

提示:

1、变长参数只能传递任意数量的同一种类型的实参值;

2、一个方法最多只能有一个变长参数,且变长参数必须位于最后。

3、重载的方法,如果有变长参数,还有非变长参数,则优先匹配非变长参数的方法。

public static void main(String[] args) {
    showNames();
    showNames("张三");
    showNames("张三", "李四", "王五");
    showScores("赵六",23.5f);
}

public static void showScores(String name,float... scores){
    System.out.println("float... scores");
}

public static void showScores(String name,float scores){
    System.out.println("float scores");
}

4.4 数组元素的访问

数组分配内存空间时,肯定是连续的内存空间。

int[] array=new int[100];

数组名array是个引用变量,它保存了堆内存中数组对象的首地址。

每个存储单元占4个字节(int);

当程序中访问 array[6] 元素时,直接计算 array+6*4 的结果就是对应存储单元的内存地址。

访问数组中的任意元素,都是根据地址直接访问对应的内存,因此速度极快。

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值