当前位置: 首页 > news >正文

数据结构与算法分析之排序算法

1. 冒泡排序

  • 理论:
    • 比较相邻的元素。如果前一个元素比后一个元素大,就交换这两个元素的位置
    • 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对元素。最终最后位置的元素就是最大值。
  • 演示:
    在这里插入图片描述
  • 代码实现:
package com.tiger.study.DataStructure.Sort;

public class BubbleSort {
    /*
    * 对数据a中元素进行排序
    * */
    public static void sort(Comparable[] a) {
        for (int i = a.length - 1; i > 0; i--) {
            for (int j = 0; j < i; j++) {
                // 比较j和j+1的值
                if (greater(a[j], a[j + 1])) {
                    exch(a, j, j + 1);
                }
            }
        }
    }

    /*
    * 比较v元素是否大于w元素
    * */
    private static boolean greater(Comparable v, Comparable w) {
        return v.compareTo(w) > 0;
    }

    /*
    * 数组元素i和j交换位置
    * */
    private static void exch(Comparable[] a, int i, int j) {
        Comparable temp;
        temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
}

2. 选择排序

  • 理论:
    • 每次遍历的过程中,都假定第一个索引处的元素是最小值,和其他索引处的值依次进行比较,如果当前索引处的值大于其他某个索引处的值,则假定其他某个索引处的值为最小值,最后可以找到最小值所在的索引。
    • 交换第一个索引处和最小值所在的索引处的值
  • 演示:
    在这里插入图片描述
  • 代码实现:
package com.tiger.study.DataStructure.Sort;

public class SelectSort {
    // 排序
    public static void sort(Comparable[] a) {
        for (int i = 0; i < a.length - 1; i++) {
            int minIndex = i;  // 定义一个变量记录最小元素的索引
            for (int j = i + 1; j < a.length; j++) {
                if (greater(a[minIndex], a[j])) {
                    minIndex = j;
                }
            }
            exch(a, minIndex, i);
        }
    }

    /*
     * 比较v元素是否大于w元素
     * */
    private static boolean greater(Comparable v, Comparable w) {
        return v.compareTo(w) > 0;
    }

    /*
     * 数组元素i和j交换位置
     * */
    private static void exch(Comparable[] a, int i, int j) {
        Comparable temp;
        temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
}

3. 插入排序

  • 理论:
    • 把所有元素分为两组,已经排序和未排序的
    • 找到未排序的组中的第一个元素,向已经排序的组中进行插入
    • 倒叙遍历已经排序的元素,依次和待插入元素进行比较,直到找到一个元素小于等于待插入元素,那么就把待插入元素放到这个位置,其他元素向后移动一位。
  • 演示:
    在这里插入图片描述
  • 代码实现:
package com.tiger.study.DataStructure.Sort;

public class InsertSort {
    // 排序
    public static void sort(Comparable[] a) {
        for (int i = 1; i < a.length; i++) {
            for (int j = i; j > 0; j--) {
                if (greater(a[j - 1], a[j])) {
                    exch(a, j - 1, j);
                } else {
                    break;
                }
            }
        }
    }

    /*
     * 比较v元素是否大于w元素
     * */
    private static boolean greater(Comparable v, Comparable w) {
        return v.compareTo(w) > 0;
    }

    /*
     * 数组元素i和j交换位置
     * */
    private static void exch(Comparable[] a, int i, int j) {
        Comparable temp;
        temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
}

4. 希尔排序

  • 理论:
    • 选定要给增长量h,按照增长量h作为数据分组的依据对数据进行分组
    • 对分好组的每一组数据完成插入排序
    • 减小增长量,最小减为1,重复第二步操作
  • 演示:
    在这里插入图片描述
  • 代码演示(包含了增长量的确定和减小规则):
package com.tiger.study.DataStructure.Sort;

public class ShellSort {
    public static void sort(Comparable[] a) {
        int h = getH(a.length);
        while (h >= 1) {
            // 排序
            // 找到待插入元素
            for (int i = h; i < a.length; i++) {
                // 把待插入的元素插入到有序数列中
                for (int j = i; j >= h; j-=h) {
                    // 待插入的元素是a[j], 比较a[j]和a[j -h]
                    if (greater(a[j - h], a[j])) {
                        exch(a, j - h, j);
                    } else {
                        break;
                    }
                }
            }
            h = h / 2;
        }
    }

    public static int getH(int len) {
        int h = 1;
        while (h < (len / 2)) {
            h = 2 * h + 1;
        }
        return h;
    }

    /*
     * 比较v元素是否大于w元素
     * */
    private static boolean greater(Comparable v, Comparable w) {
        return v.compareTo(w) > 0;
    }

    /*
     * 数组元素i和j交换位置
     * */
    private static void exch(Comparable[] a, int i, int j) {
        Comparable temp;
        temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
}

5. 归并排序

  • 原理:
    • 尽可能的一组数据拆分成两个元素相等的子组,并对每一个子组继续拆分,直到拆分后每一个子组元素个数为1
    • 将相邻的两个子组进行合并成一个有序的大组
    • 不断重复步骤2,直到最终只有一个组为止
  • 演示:
    在这里插入图片描述
  • 代码演示:
package com.tiger.study.DataStructure.Sort;


/*
*
* */


public class MergeSort {
    public static void main(String[] args) {
        // 归并排序
        int[] arr = {24, 17, 40, 28, 13, 14, 22, 32, 40, 21, 48, 4, 47, 8, 37, 18};
        int[] result = new int[arr.length];
        mergeSort(arr, 0, arr.length - 1, result);
        for (int i = 0; i < result.length; i++) {
            System.out.println(result[i]);
        }
    }

    // 递归方法
    private static void mergeSort(int[] arr, int left, int right, int[] result) {
        // 递归结束条件
        if (right == left) return;
        int mid = (right + left) / 2;

        mergeSort(arr, left, mid, result);
        mergeSort(arr, mid + 1, right, result);
        merge(arr, left, right, result);
    }

    // 合并有序的部分
    private static void merge(int[] arr, int left, int right, int[] result) {
        int mid = (right + left) / 2;
        int left_head = left, right_head = mid + 1, result_index = left;
        while (left_head <= mid && right_head <= right) {
            if (arr[left_head] <= arr[right_head]) {
                result[result_index++] = arr[left_head++];
            } else {
                result[result_index++] = arr[right_head++];
            }
        }

        if (left_head <= mid) {
            for (int i = left_head; i <= mid; i++) {
                result[result_index++] = arr[i];
            }
        }

        if (right_head <= right) {
            for (int i = right_head; i <= right; i++) {
                result[result_index++] = arr[i];
            }
        }

        for (int i = left; i <= right; i++) {
            arr[i] = result[i];
        }

    }


}

6. 快速排序

  • 原理
    • 首先设定一个分界值,通过该分界值将数组分为左右两个部分
    • 将大于或等于分界值的数据放到数组右边,小于分界值的数据放到数组的左边。此时左边部分各个元素都小于或等于分界值,而右边部分中各个元素都大于或等于分界值
    • 然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
    • 重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左侧和右侧两个部分的数据排完序后,整个数组的排序也就完成了
  • 演示
    在这里插入图片描述
  • 代码实现
package com.tiger.study.DataStructure.Sort;


// 快速排序:有一个数组,我们选择一个主元(可以固定的选,也可以随机选),然后我们将主元右边全部放置比主元小的数,左边放置比主元大的数,递归求解,最终合并就是有序的


import java.util.Random;

public class QuickSort {
    public static void main(String[] args) {
        int[] arr = {2, 6, 7, 1, 3, 5, 6, 4};
//        int[] arr = {4, 3, 2, 1};
        quickSort(arr, 0, arr.length - 1);
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }

        System.out.println("=====");
        quickSortRandom(arr, 0, arr.length - 1);
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }

    // 固定主元
    private static void quickSort(int[] arr, int left, int right) {
        if (left >= right) return;
        int mainEleIndex = partition(arr, left, right);
        quickSort(arr, left, mainEleIndex - 1);
        quickSort(arr, mainEleIndex + 1, right);
    }

    private static int partition(int[] arr, int left, int right) {
        int mainEleIndex = right;
        int i = left - 1, j = left;
        while (j < right) {
            if (arr[mainEleIndex] > arr[j]) {
                int temp = arr[i + 1];
                arr[i + 1] = arr[j];
                arr[j] = temp;
                j++;
                i++;
            } else {
                j++;
            }
        }
        int temp = arr[i + 1];
        arr[i + 1] = arr[mainEleIndex];
        arr[mainEleIndex] = temp;
        return i + 1;
    }

    // 随机主元
    private static void quickSortRandom(int[] arr, int left, int right) {
        if (left >= right) return;
        int mainEleIndex = partitionRandom(arr, left, right);
        quickSort(arr, left, mainEleIndex - 1);
        quickSort(arr, mainEleIndex + 1, right);
    }

    private static int partitionRandom(int[] arr, int left, int right) {
        Random random = new Random();
        int mainEleIndex = left + random.nextInt(right - left + 1);
        int i = left - 1, j = left;
        while (j < right) {
            if (arr[mainEleIndex] > arr[j]) {
                int temp = arr[i + 1];
                arr[i + 1] = arr[j];
                arr[j] = temp;
                j++;
                i++;
            } else {
                j++;
            }
        }
        int temp = arr[i + 1];
        arr[i + 1] = arr[mainEleIndex];
        arr[mainEleIndex] = temp;
        return i + 1;
    }
}

相关文章:

  • 利用STM32CubeMX快速创建点灯带调试输出工程案例
  • new 和 delete 为什么要匹配使用
  • 00后表示真干不过,部门新来的00后测试员已把我卷崩溃,想离职了...
  • 3年测试在职,月薪还不足20K,惨遭裁员,用亲身经历给大家提个醒..
  • 【从小白到大白03】类和对象-下
  • [DAX] MAX函数 | MAXX函数
  • Pytorch实战 | 第4天:猴痘病识别
  • 【C ++基础】第五篇 类和对象 日期计算器
  • SpringBoot+Vue实现前后端分离大学信息及院校推荐网站
  • 编程初学者如何缓解迷茫和焦虑?墙裂推荐此文,助你赢在起跑线
  • [创业之路-42] 创业是只有一小部分人活下来的游戏,探究创业失败的20个主要原因与提高成功率
  • FPGA实现SPI协议
  • 2022年金砖国家职业技能大赛(决赛)网络空间安全赛项 | 浙江赛区选拔赛 任务书
  • 第8章 聚合函数
  • Turbot4机器人入门教程-应用-读取图片文件并发布图像话题
  • ES6指北【2】—— 箭头函数
  • JS 中的深拷贝与浅拷贝
  • [Vue CLI 3] 配置解析之 css.extract
  • Android框架之Volley
  • DOM的那些事
  • Iterator 和 for...of 循环
  • JavaScript 基础知识 - 入门篇(一)
  • Python连接Oracle
  • Yii源码解读-服务定位器(Service Locator)
  • 程序员最讨厌的9句话,你可有补充?
  • 开源地图数据可视化库——mapnik
  • 前端
  • 前端技术周刊 2019-01-14:客户端存储
  • 日剧·日综资源集合(建议收藏)
  • 时间复杂度与空间复杂度分析
  • 在electron中实现跨域请求,无需更改服务器端设置
  • # Maven错误Error executing Maven
  • # 再次尝试 连接失败_无线WiFi无法连接到网络怎么办【解决方法】
  • ###C语言程序设计-----C语言学习(3)#
  • #在线报价接单​再坚持一下 明天是真的周六.出现货 实单来谈
  • (2021|NIPS,扩散,无条件分数估计,条件分数估计)无分类器引导扩散
  • (8)STL算法之替换
  • (java)关于Thread的挂起和恢复
  • (NSDate) 时间 (time )比较
  • (Redis使用系列) Springboot 整合Redisson 实现分布式锁 七
  • (附源码)springboot电竞专题网站 毕业设计 641314
  • (转)MVC3 类型“System.Web.Mvc.ModelClientValidationRule”同时存在
  • (转载)虚函数剖析
  • .bat批处理(七):PC端从手机内复制文件到本地
  • .net framework profiles /.net framework 配置
  • .NET/C# 中你可以在代码中写多个 Main 函数,然后按需要随时切换
  • .net操作Excel出错解决
  • .NET的数据绑定
  • .NET开源全面方便的第三方登录组件集合 - MrHuo.OAuth
  • .NET轻量级ORM组件Dapper葵花宝典
  • .NET中统一的存储过程调用方法(收藏)
  • @autowired注解作用_Spring Boot进阶教程——注解大全(建议收藏!)
  • @selector(..)警告提示
  • [ 隧道技术 ] cpolar 工具详解之将内网端口映射到公网
  • [100天算法】-不同路径 III(day 73)