DSAA b Elementary sort Feedback (SUStech)

(代码和图片来自何老师)

一. 各种简单比较

比较器的实现 comparable API 以及交换方法

v.compareTo(w)

return 0 if same

return 1 if v>w

return -1 if v<w

private static boolean less (Comparable v, Comparable w)
{ 
return v.compareTo(w) < 0;
 }
private static void exch (Comparable[] a, int i, int j) {
Comparable swap = a[i];
a[i] = a[j];
a[j] = swap;
}
  1. selection sort

从左到右每次循环找出后面最小的数并且与循环次数i交换

public static void sort (Comparable[] a) {
int N = a.length;
for (int i = 0; i < N; i++) {
 int min = i;
 for (int j = i+1; j < N; j++)
 if (less(a[j], a[min]))
 min = j;
exch( a, i, min);
}
}
  1. insertion sort

从左到右i次循环,将前i-1个元素与第i个元素进行比较,让前i个元素排列有序

public static void sort (Comparable[] a) {
int N = a.length;
for (int i = 0; i < N; i++)
 for (int j = i; j > 0; j--)
  if (less(a[j], a[j-1]))
     exch( a, j, j-1);
  else break;
}
  1. shell sort

设定一个h值作为评判标准,在每一次循环当中,从第i个元素开始(i=h),将i,i-h,i-2h...进行排序,并逐一递加i直到全部迭代完。

for (int i = h; i < N; i++) {
for (int j = i; j >= h && less(a[j], a[j-h]); j -= h)
exch( a, j, j-h);
}

之后对h的数值进行更改,并且再次重述上述操作,下面实例以每次将h除以3

public static void sort (Comparable[] a) {
int N = a.length;
int h = 1; 
while (h < N/3) h = 3*h + 1; // 1, 4, 13, 40, 121, 364, ...
 while (h >= 1) {
 // h-sort the array.
 for (int i = h; i < N; i++) { 
  for (int j = i; j >= h && less(a[j], a[j-h]); j -= h)
  exch( a, j, j-h);
  }
 h = h/3;
}
}

对于三种排序方式,时间复杂度如上,可见如果出现最差情况会大幅度影响计算速度,因此可以使用shuffling 操作对数组进行打乱洗牌以求不出现最差情况、

二. merge sort

merge 即将两个各自排好序的数组进行合并

private static void merge(Comparable[] a, Comparable[] aux, int lo, int mid, int hi) {
 for (int k = lo; k <= hi; k++)
     aux[k] = a[k];
 int i = lo, j = mid+1;
 for (int k = lo; k <= hi; k++) {
  if (i > mid)                   a[k] = aux[j++];
  else if (j > hi)               a[k] = aux[i++];
  else if (less(aux[j], aux[i])) a[k] = aux[j++];
  else                           a[k] = aux[i++];
  }
}

merge sort的思想即是递归调用sort 之后逐一对小数组进行合并

public class Merge {
private static void merge (...) {
/* as before */
}
private static void sort(Comparable[] a, Comparable[] aux, int lo, int hi) {
if (hi <= lo) return;
int mid = lo + (hi - lo) / 2;
sort(a, aux, lo, mid);
sort(a, aux, mid+1, hi);
if (!less(a[mid+1], a[mid])) return;//如果两个数组前一个的最大值小于后一个最小值不需要排序
merge(a, aux, lo, mid, hi);
}
public static void sort (Comparable[] a) {
Comparable[] aux = new Comparable[a.length];
sort( a, aux, 0, a.length - 1);
}
}

三. quick sort

以第一个元素为基准,对于数组后续元素进行查找,如果前端有一个大于基准元素的则会与后面小于基准元素的元素进行互换,设置出循环条件之后即可

实现:partition 方法 返回基准元素的所在位置

代码如下,逐一递归:

public class Quick {
private static int partition(Comparable[] a, int lo, int hi) {
/* see previous slide */
}
public static void sort (Comparable[] a) {
StdRandom.shuffle( a);
sort( a, 0, a.length - 1);
}
private static void sort (Comparable[] a, int lo, int hi) {
if (hi <= lo) return;
if (hi <= lo + CUTOFF - 1) {
Insertion.sort( a, lo, hi);
return;
}//添加条件,当元素较少的时候可以直接进行insertion sort 
int j = partition( a, lo, hi);
sort( a, lo, j-1);
sort( a, j+1, hi);
}
}

quick sort可以进行元素查找,例如查找在数组a中第k个元素的大小

public static Comparable select(Comparable[] a, int k)
{
StdRandom.shuffle( a);
int lo = 0, hi = a.length - 1;
while (hi > lo) {
int j = partition( a, lo, hi);
  if (j < k) lo = j + 1;
  else if (j > k) hi = j - 1;
  else return a[k];
}
return a[k];
}

由于quick sort本身的局限性,导致如果数组里面和基准元素相等的元素数量比较多,会造成反复的相同变换,因此这里有一个升级版的3-ways quick sort

原理:在数组遍历的时候,如果元素比基准元素小,则交换到相同数组之前,并且lo++

如果元素比基准元素大,则直接置换到gt后,i不变从而防止将大的置换过来未处理

如果元素等于基准元素,则将i递加,随着相同元素逐渐增多,i和lt的差距也越来越大

四. Priority queues

在介绍优先级队列之前,先来了解binary heap

二进制堆丢弃了数组的零元素,将第一个元素放置在位置1,这样的好处是让n元素的父节点为n/2,子节点为2n,2n+1,便于比较查找以及上浮下沉。

public class MaxPQ<Key extends Comparable<Key>> {
    private Key[] pq;
    private int n;

    public MaxPQ(int capacity)
    { pq = (Key[]) new Comparable[capacity+1]; }
    public boolean isEmpty()
    { return n == 0; }
    public void insert(Key x){
     pq[++n]=x;
     swim(n);
    }
    public Key delMax() {
      Key max=pq[1];
      exch(1,n--);
      sink(1);
      pq[n+1]=null;
      return max;

    }
    private void swim(int k){
        while(k>1&& less(k/2,k)){
            exch(k,k/2);
            k=k/2;
        }
    }
    private void sink(int k) {
      while(2*k<=n){
          int j=2*k;
          if (j<n&&less(j,j+1))j++;
          if (!less(k,j)) break;
          exch(k,j);
          k=j;
      }
    }


    private boolean less(int i, int j)
    { return pq[i].compareTo(pq[j]) < 0; }
    private void exch(int i, int j)
    { Key t = pq[i]; pq[i] = pq[j]; pq[j] = t; }
}

除此之外还有minpq最小堆,只需要将less的符号转换即可,有了堆之后,就可以进行heap构建以及排序

public class Heap{
public static void sort (Comparable[] a) {
  int n = a.length;
   for (int k = n/2; k >= 1; k--)
    sink( a, k, n);
    while (n > 1) {
     exch( a, 1, n);
     sink( a, 1, --n);
    }
}
private static void sink(Comparable[] a, int k, int n)
{ /* as before */ }
private static boolean less(Comparable[] a, int i, int j)
{ /* as before */ }
private static void exch(Object[] a, int i, int j)
{ /* as before */ }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值