【数据结构与算法01】排序算法

本文详细介绍了四种经典的排序算法:冒泡排序、选择排序、插入排序和归并排序,包括它们的排序原理和Java代码实现。此外,还分析了这些排序算法的稳定性,其中冒泡排序和插入排序是稳定的,而选择排序和归并排序则是不稳定的。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 冒泡排序

1.1 排序原理

  1. 比较相邻的元素。如果前一个元素比后一个元素大,就交换这两个元素的位置。
  2. 对每一对相邻元素做同样的工作,从开始第一对元素到结尾的最后一对元素。最终最后位置的元素就是最大值
  3. 需要注意的是,每次比较的次数为为排序数组长度减一
    在这里插入图片描述

1.2 代码实现

import java.util.Arrays;

public class BubbleSort {
    public static void main(String[] args) {
        int[] a ={1,3,5,7,2,6};
        Bubble(a);
        System.out.println(Arrays.toString(a));
    }

    //比如六个数,第一次比较5次,第二次比较4次。。。
    private static void Bubble(int[] a) {
        for(int i=a.length-1;i>0;i--){
            for(int j = 0;j<i;j++){
                if(a[j]>a[j+1]){
                    int temp = a[j];
                    a[j] = a[j+1];
                    a[j+1] = temp;
                }
            }
        }
    }
}

在这里插入图片描述
时间复杂度O(N^2)

2. 选择排序

2.1 排序原理

1.每一次遍历的过程中,都假定第一个索引处的元素是最小值,和其他索引处的值依次进行比较,如果当前索引处的值大于其他某个索引处的值,则假定其他某个索引出的值为最小值,最后可以找到最小值所在的索引

2.交换第一个索引处和最小值所在的索引处的值
在这里插入图片描述

2.2 代码实现

import java.util.Arrays;

public class SelectSort {
    public static void main(String[] args) {
        int[] a = {1,3,2,5,7,4};
        Select(a);
        System.out.println(Arrays.toString(a));
    }

    //假设第一个位置就是最小元素,遍历数组,寻找最小元素,找到就将第一个位置元素与最小元素交换索引
    private static void Select(int[] a) {
        for(int i = 0;i<a.length-1;i++){
            //假定本次遍历,最小值所在的索引是i
            int index = i;
            for(int j = i+1;j<a.length;j++){
                if(a[j]<a[index]){
                    //交换最小值所在的索引
                    index = j;
                }
            }
            //每次循环的i都是未排序的第一个
            int temp = a[i];
            a[i] = a[index];
            a[index] = temp;
        }
    }
}

在这里插入图片描述
时间复杂度O(N^2)

3. 插入排序

3.1 排序原理

1.把所有的元素分为两组,已经排序的和未排序的;

2.找到未排序的组中的第一个元素,向已经排序的组中进行插入;

3.倒叙遍历已经排序的元素,依次和待插入的元素进行比较,直到找到一个元素小于等于待插入元素,那么就把待插入元素放到这个位置,其他的元素向后移动一位;
在这里插入图片描述

3.2 代码实现

import java.util.Arrays;

public class InsertSort {
    public static void main(String[] args) {
        int [] a = {1,4,3,6,2,5};
        Insert(a);
        System.out.println(Arrays.toString(a));
    }

    //默认第一个元素有序,从第二个开始,往前比较,如果比他大,则交换位置
    private static void Insert(int[] a) {
        //由于默认认为第一个是有序的,则从第二个元素开始比较,因此循环从1开始
        for(int i = 1;i<a.length;i++){
            for(int j = i;j>0;j--){
                if(a[j]<a[j-1]){
                    int temp = a[j];
                    a[j] = a[j-1];
                    a[j-1] = temp;
                }
            }
        }
    }
}

在这里插入图片描述
时间复杂度O(N^2)

4. 归并排序

归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

4.1 排序原理

1.尽可能的一组数据拆分成两个元素相等的子组,并对每一个子组继续拆分,直到拆分后的每个子组的元素个数是1为止。
2.将相邻的两个子组进行合并成一个有序的大组;
3.不断的重复步骤2,直到最终只有一个组为止。
在这里插入图片描述
如何治呢?我们看下一张图
在这里插入图片描述

4.2 代码实现

import java.util.Arrays;

public class mergeSort {
    public static void main(String[] args) {
        int[] a = {1, 3, 2, 5, 4, 6, 8, 7};
        int[] temp = new int[a.length];
        int left = 0;
        int right = a.length-1;
        MergeSort(a,left,right,temp);
        System.out.println(Arrays.toString(a));

    }
    public static void MergeSort(int[] arr,int left,int right,int[] temp){
        if(left<right){
            int mid = (left+right)/2;
            //分
            MergeSort(arr,left,mid,temp);
            MergeSort(arr,mid+1,right,temp);
            //治
            Merge(arr,left,mid,right,temp);
        }

    }
//如何治:分三步
    public static void Merge(int[] arr, int left, int mid, int right, int[] temp) {
        int i = left;
        int j = mid + 1;
        int t = 0;

        //1. 先把左右两边的有序数据按规则填到temp数组,直到有一方填完为止
        while (i <= mid && j <= right) {
            if (arr[i] < arr[j]) {
                temp[t] = arr[i];
                t++;
                i++;
            } else {
                temp[t] = arr[j];
                t++;
                j++;
            }
        }

        //2. 把有剩余数据一边的剩余数据拷贝到临时数组
        while (i <= mid) {
            temp[t] = arr[i];
            t++;
            i++;
        }
        while (j <= right) {
            temp[t] = arr[j];
            t++;
            j++;
        }

        //3. 把temp数组拷贝回arr数组,不是每次都拷贝所有
        t = 0;
        int tempLeft = left;
        while (tempLeft <= right) {
            arr[tempLeft] = temp[t];
            tempLeft++;
            t++;
        }
    }
}

在这里插入图片描述
时间复杂度O(nlogn),代价就是用空间换时间。

5. 排序算法稳定性分析

冒泡排序:
只有当arr[i]>arr[i+1]的时候,才会交换元素的位置,而相等的时候并不交换位置,所以冒泡排序是一种稳定排序算法。

选择排序:
选择排序是给每个位置选择当前元素最小的,例如有数据{5(1),8 ,5(2), 2, 9 },第一遍选择到的最小元素为2,所以5(1)会和2进行交换位置,此时5(1)到了5(2)后面,破坏了稳定性,所以选择排序是一种不稳定的排序算法。

插入排序:
比较是从有序序列的末尾开始,也就是想要插入的元素和已经有序的最大者开始比起,如果比它大则直接插入在其后面,否则一直往前找直到找到它该插入的位置。如果碰见一个和插入元素相等的,那么把要插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。

归并排序:
归并排序在归并的过程中,只有arr[i]<arr[i+1]的时候才会交换位置,如果两个元素相等则不会交换位置,所以它并不会破坏稳定性,归并排序是稳定的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值