五种排序算法

冒泡排序只会操作相邻的两个数据。每次冒泡操作都会对相邻的两个元素进行比较,看是否满足大小关系要求。如果不满足就让它俩互换。一次冒泡会让至少一个元素移动到它应该在的位置,重复n次,就完了n个数据的排序工作。
在这里插入图片描述

// 冒泡排序,a 表示数组,n 表示数组大小
public void bubbleSort(int[] a, int n) {
  if (n <= 1) return;
for (int i = 0; i < n; ++i) {
    // 提前退出冒泡循环的标志位
    boolean flag = false;
    for (int j = 0; j < n - i - 1; ++j) {
      if (a[j] > a[j+1]) { // 交换
        int tmp = a[j];
        a[j] = a[j+1];
        a[j+1] = tmp;
        flag = true;  // 表示有数据交换      
      }
    }
    if (!flag) break;  // 没有数据交换,提前退出
  }
}

插入排序是将数组中的数据分为两个区间,已排序区间和未排序区间。初始已排序区间只有一个元素,就是数据的第一个元素。插入算法的核心思想是取未排序区间中的元素,在已排序区间中找到合适的插入位置将其插入,并保证已排序区间一直有序。重复这个过程,直到未排序区间中元素为空,算法结束。
在这里插入图片描述

// 插入排序,a 表示数组,n 表示数组大小
public void insertionSort(int[] a, int n) {
  if (n <= 1) return;

  for (int i = 1; i < n; ++i) {
    int value = a[i];
    int j = i - 1;
    // 查找插入的位置
    for (; j >= 0; --j) {
      if (a[j] > value) {
        a[j+1] = a[j];  // 数据移动
      } else {
        break;
      }
    }
    a[j+1] = value; // 插入数据
  }
}

选择排序算法的实现思路有点类似插入排序,也分为已排序区间和未排序区间。但是选择排序每次会从未排序区间中找到最小的元素,将其放到已排序区间的末尾。
在这里插入图片描述

//选择排序
public void selectionSort(int[] a,int n){
    if(n<=1) return;
    for(int i=0;i<n-1;++i){
    //查找最小值
        int minIndex=i;
        for(int j=i+1;j<n;++j){
            if(a[j]<a[minIndex]){
                minIndex=j;
            }
        }
        //交换
        int tmp=a[i];
        a[i]=a[minIndex];
        a[minIndex]=tmp;
    }
}

归并排序:
归并排序的核心思想,是把数组从中间开始分成两部分,然后分别排序,在合并在一起。归并使用到的就是分治的思想。分治,顾名思义,就是分而治之,将一个大问题分解成小的问题。小的问题解决了,大问题也就解决了。
在这里插入图片描述

//递归调用函数
private static void mergeSortInternally(int[] a,int p,int r){
    //递归终止条件
    if(p>=r) return;
    //取p到r之间的中间位置q,防止(p+r)的和超过int类型最大值
    int q=p+(r-p)/2;
    //分治递归
    mergeSortInternally(a,p,q);
    mergeSortInternally(a,q+1,r);

    //将A[p...q]和A[q+1...r]合并为A[p...r]
    merge(a,p,q,r);
}
private static void merge(int[] a,int p,int q,int r){
    int i=p;
    int j=q+1;
    int k=0;//初始化变量i,j,k
    int[] tmp=new int[r-p+1];//申请一个大小跟a[p...r]一样的临时数组
    while(i<=q&&j<=r){
        if(a[i]<=a[j]){
            tmp[k++]=a[i++];
        }else{
            tmp[k++]=a[j++];
        }
    }
    //判断哪个子数组中有剩余的数据
    int start=i;
    int end=q;
    if(j<=r){
        start=j;
        end=r;
    }

    //将剩余的数据拷贝到临时数组tmp
    while (start<=end){
        tmp[k++] =a[start++];
     }

    //将tmp中的数组拷贝回a[p...r]
    for(i=0;i<r-p;++i){
        a[p+i]=tmp[i];
    }
}

快速排序
快排的思想是这样的:如果要排序数组下标从p到r之间的一组数据,我们选择p到r之间的任意一个数据作为pivot(分区点)。
我们遍历p到r之间的数据,将小于pivot的放到左边,将大于pivot的放到右边,将pivot放到中间。经过这一步骤之后,数组p到r之间的数据就被分成了三个部分,前面p到q-1之间都是小于pivot的,中间是pivot,后面的q+1到r之间是大于pivot的。
在这里插入图片描述

private static void quickSortInternally(int[] a,int p,int r){
    if(p>=r) return;

    int q=partition(a,p,r);//获取分区点
    quickSortInternally(a,p,q-1);
    quickSortInternally(a,q+1,r);
}

private static int partition(int[] a,int p,int r){
    int pivot=a[r];
    int i=p;
    for(int j=p;j<r;++j){
        if(a[j]<pivot){
            if(i==j){
                ++i;
            }else{
                int tmp=a[i];
                a[i++]=a[j];
                a[j]=tmp;
            }
        }
    }

    int tmp=a[i];
    a[i]=a[r];
    a[r]=tmp;
    System.out.println("i="+i);
    return i;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值