IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 冒泡排序、快排、堆排序以及归并排序的Java实现 -> 正文阅读

[数据结构与算法]冒泡排序、快排、堆排序以及归并排序的Java实现

前言:本文以升序排序为例讲解了几种排序算法的java实现,建议读者先了解各种排序算法的原理先,然后结合原理来读取本文的代码,效果更佳。

由于多次使用到交换数组中的两个元素的值,故先实现交换函数:

//交换数组中两个元素
private static void swap(int[] arr, int a, int b) {
        int t = arr[a];
        arr[a] = arr[b];
        arr[b] = t;
    }

一、冒泡排序

/**
     * 冒泡排序
     * @param arr 待排序数组
     */
    private static void bubbleSort(int[] arr) {
        int len = arr.length;
        boolean flag = true;//用于剪枝:记录该轮是否有元素交换,若无:可直接结束
        for (int i=1;flag && i<len;i++) {//冒泡排序趟数,len个数最多进行len-1趟
            flag = false;//每轮开始设置标志位false
            for (int j=0;j<len-i;j++) {
                if(arr[j] > arr[j+1]) {//若当前元素比后一个元素大,则交换两元素,并设置标志位true
                    swap(arr, j, j+1);
                    flag = true;
                }
            }
        }
 
    }

测试方法:

public static void main(String[] args) {
        int[] arr = {11,44,23,67,88,65,9,12,13,16,13,9,53,68};
        System.out.println("原始数组:");
        System.out.println(Arrays.toString(arr));
        bubbleSort(arr);
        System.out.println("冒泡排序后:");
        System.out.println(Arrays.toString(arr));
    }

输出结果:

二、快速排序

?

/**
     * 快速排序
     * @param arr 待排序数组
     * @param low 数组中待排序最低位置
     * @param high 数组中待排序最高位置
     */
    private static void quickSort(int[] arr, int low, int high) {
        if (low >= high) return;//递归终止条件
        int l = low, r = high, temp = arr[low];//设置变量记录low、high和要确定位置的元素值
        while (l < r) {
            while (l<r && arr[r]>=temp) r--;//当前位置合理且值大于等于temp直接跳过
            while (l<r && arr[l]<=temp) l++;//同上
            if (l < r) {//若l和r未相遇,则交换对应位置的两个值
                swap(arr, l, r);
            }
        }
        //将本轮要确定的值放入最终位置
        arr[low] = arr[l];
        arr[l] = temp;
        //继续递归
        quickSort(arr, low, l-1);
        quickSort(arr, l+1, high);
    }

测试方法:

public static void main(String[] args) {
        int[] arr = {11,44,23,67,88,65,9,12,13,16,13,9,53,68};
        System.out.println("原始数组:");
        System.out.println(Arrays.toString(arr));
//        bubbleSort(arr);
//        System.out.println("冒泡排序后:");
        quickSort(arr,0,arr.length-1);
        System.out.println("快速排序后:");
        System.out.println(Arrays.toString(arr));
    }

输出结果:

三、堆排序

堆排序中要经常调整堆,所以我们先来实现这个调整堆的方法,代码如下:

/**
     * 用于调整堆的方法
     * @param arr 待排序数组(待调整数组)
     * @param cur 当前需要调整的数据的下标
     * @param max 参与调节(比较)的最大范围+1
     */
    private static void adjustHeap (int[] arr, int cur, int max) {
        int temp = arr[cur];//先将要调整的数据存入临时变量
        for (int i=2*cur+1;i<max;i=i*2+1) {//获取当前结点的左子结点
            //如果当前结点存在右子结点且值大于左子结点,则将索引指向右子结点
            if (i+1<max && arr[i+1]>arr[i]) i++;
            if (arr[i] > temp) {//判断当前子结点值是否大于自己的值
                arr[cur] = arr[i];//使当前值等于大于自己的子结点值
                cur = i;//将当前值索引指向与自己交换的子结点的位置
            } else break;//若不需要交换,提前结束
        }
        arr[cur] = temp;//最后将要调整的数据放入当前所指向的位置
    }

?堆排序方法的代码如下:

/**
     * 堆排序
     * @param arr 待排序的数组
     */
    private static void heapSort(int[] arr) {
        int len = arr.length;
        //从第一个非叶子结点自底向上依次进行调整,最后得到一个大顶堆
        for (int i=len/2-1;i>=0;i--) {
            adjustHeap(arr, i, len);
        }
        //len个元素进行len-1次交换和维护后得到一个升序的数组
        for (int i=1;i<len;i++) {
            swap(arr, 0, len-i);//交换对顶元素和最后一个元素
            //调整堆顶元素,使其依然是大顶堆(最后i个元素不参与调整)
            adjustHeap(arr, 0, len-i);
        }
    }

测试方法:

public static void main(String[] args) {
        int[] arr = {11,44,23,67,88,65,9,12,13,16,13,9,53,68};
        System.out.println("原始数组:");
        System.out.println(Arrays.toString(arr));
//        bubbleSort(arr);
//        System.out.println("冒泡排序后:");
//        quickSort(arr,0,arr.length-1);
//        System.out.println("快速排序后:");
        heapSort(arr);
        System.out.println("堆排序后:");
        System.out.println(Arrays.toString(arr));
    }

输出结果:

?

四、归并排序

归并排序需要用到一个合并两个有序子序列到一个有序子序列中的方法,代码如下:

/**
     * 合并两个有序子序列到一个有序子序列(临时数组)中
     * @param arr 待排序数组
     * @param low 将要排序的最低下标
     * @param mid 两个子子序列的分界值
     * @param high 将要排序的最高下标
     */
    private static void merger(int[] arr, int low, int mid, int high){
        //创建一个临时数组,用于存放两个子序列排序后的结果
        int[] temp = new int[high-low+1];
        //分别设置索引指向两个已经排好序的子序列的起始位置,并设置tI指向temp中的位置
        int lowI = low, highI = mid+1, tI = 0;
        //若两个索引都未达到上边界值,则循环比较
        while (lowI<=mid && highI<=high) {
            //将两个子序列中较小的值放入临时数组,并将对应索引加一
            if (arr[lowI] < arr[highI]) {
                temp[tI++] = arr[lowI++];
            } else {
                temp[tI++] = arr[highI++];
            }
        }
        //判断哪个子序列还没有遍历完,然后遍历该子序列
        if (lowI <= mid) {
            while (lowI <= mid) {
                temp[tI++] = arr[lowI++];
            }
        } else {
            while (highI <= high) {
                temp[tI++] = arr[highI++];
            }
        }
        //将临时数组中有序的元素更新到arr的相应位置中
        for (int i=0;i<tI;i++) {
            arr[low+i] = temp[i];
        }
    }

归并排序的总体方法代码:

/**
     * 归并排序
     * @param arr 待排序数组
     * @param low 待排序序列的最小下标
     * @param high 待排序序列的最大下标
     */
    private static void mergeSort(int[] arr, int low, int high) {
        if (low < high) {//判断是否满足条件
            int mid = low + (high-low)/2;//计算中间值
            mergeSort(arr, low, mid);//递归对左边序列进行归并排序
            mergeSort(arr, mid+1, high);//递归对右边序列进行归并排序
            merger(arr, low, mid, high);//合并两个子序列
        }
    }

测试方法:

public static void main(String[] args) {
        int[] arr = {11,44,23,67,88,65,9,12,13,16,13,9,53,68};
        System.out.println("原始数组:");
        System.out.println(Arrays.toString(arr));
//        bubbleSort(arr);
//        System.out.println("冒泡排序后:");
//        quickSort(arr,0,arr.length-1);
//        System.out.println("快速排序后:");
//        heapSort(arr);
//        System.out.println("堆排序后:");
        mergeSort(arr, 0, arr.length-1);
        System.out.println("归并排序后:");
        System.out.println(Arrays.toString(arr));
    }

输出结果:

?五、全部代码

public class TestClass {

    public static void main(String[] args) {
        int[] arr = {11,44,23,67,88,65,9,12,13,16,13,9,53,68};
        System.out.println("原始数组:");
        System.out.println(Arrays.toString(arr));
//        bubbleSort(arr);
//        System.out.println("冒泡排序后:");
//        quickSort(arr,0,arr.length-1);
//        System.out.println("快速排序后:");
//        heapSort(arr);
//        System.out.println("堆排序后:");
        mergeSort(arr, 0, arr.length-1);
        System.out.println("归并排序后:");
        System.out.println(Arrays.toString(arr));
    }

    /**
     * 归并排序
     * @param arr 待排序数组
     * @param low 待排序序列的最小下标
     * @param high 待排序序列的最大下标
     */
    private static void mergeSort(int[] arr, int low, int high) {
        if (low < high) {//判断是否满足条件
            int mid = low + (high-low)/2;//计算中间值
            mergeSort(arr, low, mid);//递归对左边序列进行归并排序
            mergeSort(arr, mid+1, high);//递归对右边序列进行归并排序
            merger(arr, low, mid, high);//合并两个子序列
        }
    }
    
    /**
     * 合并两个有序子序列到一个有序子序列(临时数组)中
     * @param arr 待排序数组
     * @param low 将要排序的最低下标
     * @param mid 两个子子序列的分界值
     * @param high 将要排序的最高下标
     */
    private static void merger(int[] arr, int low, int mid, int high){
        //创建一个临时数组,用于存放两个子序列排序后的结果
        int[] temp = new int[high-low+1];
        //分别设置索引指向两个已经排好序的子序列的起始位置,并设置tI指向temp中的位置
        int lowI = low, highI = mid+1, tI = 0;
        //若两个索引都未达到上边界值,则循环比较
        while (lowI<=mid && highI<=high) {
            //将两个子序列中较小的值放入临时数组,并将对应索引加一
            if (arr[lowI] < arr[highI]) {
                temp[tI++] = arr[lowI++];
            } else {
                temp[tI++] = arr[highI++];
            }
        }
        //判断哪个子序列还没有遍历完,然后遍历该子序列
        if (lowI <= mid) {
            while (lowI <= mid) {
                temp[tI++] = arr[lowI++];
            }
        } else {
            while (highI <= high) {
                temp[tI++] = arr[highI++];
            }
        }
        //将临时数组中有序的元素更新到arr的相应位置中
        for (int i=0;i<tI;i++) {
            arr[low+i] = temp[i];
        }
    }

    /**
     * 堆排序
     * @param arr 待排序的数组
     */
    private static void heapSort(int[] arr) {
        int len = arr.length;
        //从第一个非叶子结点自底向上依次进行调整,最后得到一个大顶堆
        for (int i=len/2-1;i>=0;i--) {
            adjustHeap(arr, i, len);
        }
        //len个元素进行len-1次交换和维护后得到一个升序的数组
        for (int i=1;i<len;i++) {
            swap(arr, 0, len-i);//交换对顶元素和最后一个元素
            //调整堆顶元素,使其依然是大顶堆(最后i个元素不参与调整)
            adjustHeap(arr, 0, len-i);
        }
    }

    /**
     * 用于调整堆的方法
     * @param arr 待排序数组(待调整数组)
     * @param cur 当前需要调整的数据的下标
     * @param max 参与调节(比较)的最大范围+1
     */
    private static void adjustHeap (int[] arr, int cur, int max) {
        int temp = arr[cur];//先将要调整的数据存入临时变量
        for (int i=2*cur+1;i<max;i=i*2+1) {//获取当前结点的左子结点
            //如果当前结点存在右子结点且值大于左子结点,则将索引指向右子结点
            if (i+1<max && arr[i+1]>arr[i]) i++;
            if (arr[i] > temp) {//判断当前子结点值是否大于自己的值
                arr[cur] = arr[i];//使当前值等于大于自己的子结点值
                cur = i;//将当前值索引指向与自己交换的子结点的位置
            } else break;//若不需要交换,提前结束
        }
        arr[cur] = temp;//最后将要调整的数据放入当前所指向的位置
    }

    /**
     * 快速排序
     * @param arr 待排序数组
     * @param low 数组中待排序最低位置
     * @param high 数组中待排序最高位置
     */
    private static void quickSort(int[] arr, int low, int high) {
        if (low >= high) return;//递归终止条件
        int l = low, r = high, temp = arr[low];//设置变量记录low、high和要确定位置的元素值
        while (l < r) {
            while (l<r && arr[r]>=temp) r--;//当前位置合理且值大于等于temp直接跳过
            while (l<r && arr[l]<=temp) l++;//同上
            if (l < r) {//若l和r未相遇,则交换对应位置的两个值
                swap(arr, l, r);
            }
        }
        //将本轮要确定的值放入最终位置
        arr[low] = arr[l];
        arr[l] = temp;
        //继续递归
        quickSort(arr, low, l-1);
        quickSort(arr, l+1, high);
    }

    /**
     * 冒泡排序
     * @param arr 待排序数组
     */
    private static void bubbleSort(int[] arr) {
        int len = arr.length;
        boolean flag = true;//用于剪枝:记录该轮是否有元素交换,若无:可直接结束
        for (int i=1;flag && i<len;i++) {//冒泡排序趟数,len个数最多进行len-1趟
            flag = false;//每轮开始设置标志位false
            for (int j=0;j<len-i;j++) {
                if(arr[j] > arr[j+1]) {//若当前元素比后一个元素大,则交换两元素,并设置标志位true
                    swap(arr, j, j+1);
                    flag = true;
                }
            }
        }
        System.out.println("冒泡排序后:");
    }

    //交换数组中两个元素
    private static void swap(int[] arr, int a, int b) {
        int t = arr[a];
        arr[a] = arr[b];
        arr[b] = t;
    }
    
}

六、总结

学习一个算法应该先理解并掌握其原理,然后动手写代码去实现该算法。由于最近比较忙,所以只编写了这几种排序算法的java代码,并没有详细的对原理进行解释。鄙人争取空闲下来后能补上这些排序算法的原理解读。最后,由于能力有限,本文若有不当之处,欢迎大家批评并指出。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-09-13 09:31:11  更:2021-09-13 09:33:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 10:00:40-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码