栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

排序基础2(归并,快排)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

排序基础2(归并,快排)

归并排序的原理和实现

对于归并排序,重点是要理解分治算法和递归处理的思想。如果要排序一个数组,那么我们首先要把数组从中间分成两段,然后对这两段分别进行排序,最后将排序好的两部分进行性别,这样整个数组就是一个有序的了。首先看一个图进行理解。

归并排序使用的是分治算法的思想。分治,就是分而治之,将一个大问题分解成一个小问题来进行解决。分治算法的思想与之前提到的递归很是相似,分治算法就是通过递归来进行实现的,分治是一种解决问题的思想,递归是一种编程技巧。

下面来看看代码

class Test{
   public void mergeSort(int[] a,int start,int end){
      if(start < end){
         int mid = (start + end)/2;
         mergeSort(a,start,mid);//左侧序列进行排序
         mergeSort(a,mid + 1,end);//右侧序列进行排序
         merge(a,start,mid,end);//合并
      }
   }
   
   public void merge(int[] a,int left,int mid,int right){
      //设置临时数组
      int[] temp = new int[a.length];
      //设置指针
      int p1 = left;
      int p2 = mid + 1;
      int k = left;//这个k指向temp数组的第一个位置
      while(p1 < mid && p2 < right){
         if(a[p1] < a[p2]){
            temp[k++] = a[p1++];
         } else {
            temp[k++] = a[p2++];
         }
      }
      //如果左边的序列还有元素没有处理完,直接加到末尾
      while(p1 < mid) temp[k++] = a[p1++];
      while(p2 < right) temp[k++] = a[p2++];

      //将temp的元素复制回a 
      for(int i : temp){
         a[i] = temp[i];
      }
   }

   @Test
   public void test(){
        int[] a = {2,3,4,5,6,2,4,5,7};
        mergeSort(a, 0, a.length-1);
        System.out.println("排好序的数组:");
        for (int e : a)
            System.out.print(e+" ");
      }
   }
}

 归并排序是稳定排序算法

时间复杂度O(nlogn)

空间复杂度O(n)

快速排序

快速排序的原理和实现

快速排序也用到了分治算法思想,下面来看看原理。

如果要排序数组中下标从p到r的数据。那么,我们选择p到r之间的任意一个数据作为pivot(分区点),然后遍历从p到r的数据,将小于pivot的数据放到左边,将大于或等于pivot的数据放到右边,将pivot放到中间。

经过处理,从p到r的数据就被分成3个部分。假设pivot目前所在的地方为q,那么p到q - 1的部分都小于pivot,q + 1到r的部分都大于pivot。如图。

根据分治的处理思想,分区完成之后,我们递归地排序下标从p到q - 1地数据和下标从q+1到r地数据,直到待排序区间大小缩小为1,这说明数组中所有地数据都有序了,下面用递推公式来表示。

quick_sort(p,r) = partition(p,r) + quick_sort(p,q-1) + quick_sort(q+1,r).

终止条件:p>=r

下面用伪代码来编写

quick_sort(A,n){
   //A代表数组,n代表大小
  quick_sort_c(A,0,n-1)
}

//快速排序递归函数,p,r为下标
quick_sort_c(A,p,r){
   if p >= r then return
   q = partition(A,p,r)//分区
   quick_sort(A,q+1,r)  
}

 partition()所做地工作就是随机选择一个元素作为pivot(一般选择p到r区间中地最后一个元素),然后基于pivot对A[p,r]分区。分区函数返回分区之后pivot地下标。

下面来看看快排实现原地分区函数

partition(A,p,r){
   pivot := A[r]
   i := p
   for j := p to r do{
      if A[j] < pivot{
        swap A[i] with A[j]
        i := i + 1
      }
   }
   swap A[i] with A[j]
   return i;
}
这里的处理有点类似选择排序。我们通过游标 i 把 A[p…r-1] 分成两部分。A[p…i-1] 的元 素都是小于 pivot 的,我们暂且叫它“已处理区间”,A[i…r-1] 是“未处理区间”。我们 每次都从未处理的区间 A[i…r-1] 中取一个元素 A[j],与 pivot 对比,如果小于 pivot,则 将其加入到已处理区间的尾部,也就是 A[i] 的位置。 数组的插入操作还记得吗?在数组某个位置插入元素,需要搬移数据,非常耗时。当时我们 也讲了一种处理技巧,就是交换,在 O(1) 的时间复杂度内完成插入操作。这里我们也借助 这个思想,只需要将 A[i] 与 A[j] 交换,就可以在 O(1) 时间复杂度内将 A[j] 放到下标为 i 的位置。 如图:

归并排序的处理过程是 由下到上 的,先处理子问题,然后再合并。而快排正好相 反,它的处理过程是 由上到下 的,先分区,然后再处理子问题。归并排序虽然是稳定的、时 间复杂度为 O(nlogn) 的排序算法,但是它是非原地排序算法。我们前面讲过,归并之所以 是非原地排序算法,主要原因是合并函数无法在原地执行。快速排序通过设计巧妙的原地分 区函数,可以实现原地排序,解决了归并排序占用太多内存的问题。

private void swap(int[] nums, int i, int j) {
    int temp = nums [i];
    nums [i] = nums [j];
    nums [j] = temp;
}


private void quickSort(int[] nums, int left, int right) {
    // 递归返回条件,和分区排序结束
    if (right-left <=0) {
        return;
    }
    // 选择数组右边界值作为分区节点
    int pivot = nums[right];
    // 从数组左边界值开始维护分区
    int partition=left-1;
    // 遍历当前分区内元素
    for (int i = left; i <= right-1; i++) {
        if ((nums [i] < pivot) ) {
            // 将小于pivot的值交换到partition左边
            // 将大于等于pivot的值交换到partition右边
            partition++;
            swap(nums, partition, i);
        }
    }
    // 将分区节点插入到数组左右分区中间
    partition++;
    swap(nums, partition, right);
    // 分区节点排序完成
    // 左分区继续排序,右分区继续排序
    quickSort(nums,left, partition-1);
    quickSort(nums,partition+1, right);
}


public int[] sortArray(int[] nums) {
    if (nums == null || nums.length ==0) {
        return nums;
    }
    quickSort(nums, 0, nums.length - 1);
    return nums;
}

快速排序不是稳定性排序算法

时间复杂度O(nlogn)

空间复杂度O(n)

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/273787.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号