六大排序实现和比较

常见的排序算法

冒泡排序

两两比较相邻记录的关键字,如果是反序则交换,直到没有反序的记录位置

public static void bubbleSort(int[] arr) {
  boolean flag = true;
  for(int i = 1; i < arr.length; i ++) {
    flag = false;
    for(int j = arr.length - 1; j <= i; j++) {
      if(arr[j - 1] > arr[j]) {
        swap(arr, j - 1, j);
      }
    }
  }
}

public static void swap(int[] arr, int i, int j) {
  int tmp = arr[i];
  arr[i] = arr[j];
  arr[j] = tmp;
}

最好时间复杂度:O(n)

最坏时间复杂度O( n 2 n^2 n2

平均时间复杂度:O( n 2 n^2 n2

空间复杂度:O(1)

稳定性:稳定

简单选择排序

通过n - i次关键字之间的比较,从n - i + 1个记录中选出关键字最小的记录,并和第i 个记录交换。

public static void selectSort(int[] arr) {
  int min;
  for(int i = 1; i < arr.length; i++) {
    min = i;
    for(int j = i + 1; j < arr.length; j++) {
      if(arr[min] > arr[j]) {
        min = j;
      }
    }
    
    if(min != i) {
      swap(arr, i, min);
    }
  }
}		

public static void swap(int arr, int i, int j) {
  int tmp = arr[i];
  arr[i] = arr[j];
  arr[j] = tmp; 
}

最好时间复杂度:O( n 2 n^2 n2

最坏时间复杂度:O( n 2 n^2 n2

平均时间复杂度:O( n 2 n^2 n2

空间复杂度:O(1)

稳定性:不稳定

直接插入排序

将n个待排序的元素看成一个有序表和无序表,从无序表中取出一个元素将其插入到有序表的指定位置,重复n-1次完成排序

public static void insertSort(int[] arr) {
  int j, tmp;
  for(int i = 1; i< arr.length; i++) {
    if(arr[i] < arr[i - 1]) {
      tmp = arr[i];
      for(j = i + 1; arr[j] > tmp; j--) {
        arr[j + 1] = arr[j];
      }
      arr[j + 1] = tmp;
    }
  }
} 

最优时间复杂度:O( n n n

最坏时间复杂度:O( n 2 n^2 n2

平均时间复杂度:O( n 2 n^2 n2

空间复杂度:O(1)

稳定性:稳定

希尔排序

取一个增量increment作为间隔将带排序列分为increment个子序列,距离increment的元素在同一子序列,对每一个子序列进行直接插入排序,然后缩小增量increment并重复上面操作,直到increment = 1

public static void shellSort(int[] arr) {
  int j, tmp, increment = arr.length;
  do {
    for(int i = increment + 1; i < arr.length; i++) {
      if(arr[i] < arr[i - increment]) {
        tmp = arr[i];
        for(j = i - increment; j > 0 && arr[j] > tmp; j -= increment) {
          arr[j + increment] = arr[j];
        }
        arr[j + increment] = tmp;
      }
    }
  } while(increment > 1);
}

最优时间复杂度:O(n)

最坏时间复杂度:O( n 2 n^2 n2

平均时间复杂度:O( n 1.3 n^{1.3} n1.3

空间复杂度:O(1)

稳定性:不稳定

归并排序

将初始序列看作是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到n/2个长度为2或1的有序子序列,再次两两归并,直到得到一个长度为n的有序序列为止

递归实现

  1. 从上到下递归
public static void mergeSortUp2Down(int[] arr, int start, int end) {
  if(arr == null || start >= end) return;
  int mid = (start + end) / 2;
  
  mergeSortUp2Down(arr, start, mid);
  mergeSortUp2Down(arr, mid + 1, end);
  merge(arr, start, mid, end);
}

public static void merge(int[] arr, int start, int mid, int end) {
  int[] temp = new int[end - start + 1];
  int i = start;
  int j = mid + 1;
  int k = 0;
  while(i <= mid && j <= end) {
    if(arr[i] < arr[j]) {
      temp[k++] = arr[i++];
    }
    else {
      temp[k++] = arr[j++];
    }
  }
  
  while(i <= mid) {
    temp[k++] = arr[i++];
  }
  
  while(j <= end) {
    temp[k++] = arr[j++];
  }
  
  for(i = 0; i < k; i++) {
    arr[start + i] = temp[i];
  }
  
  temp = null;
}
  1. 从下往上递归:
public static void mergeSortDown2Up(int[] arr) {
  for(int i = 1; i < arr.length; i *= 2) {
    mergeGroup(arr, arr.length, i);
  }
}

public static void mergeGroup(int[] arr, int len, int gap) {
  int i;
  for(i = 0; i + 2 * gap - 1 < len; i += (2 * gap)) {
    merge(arr, i, i + gap - 1, i + 2 * gap - 1);
  }
  
  if(i + gap - 1 < len - 1) {
    merge(arr, i, i + gap - 1, len - 1);
  }
}

非递归实现

public static void mergeSortNon(int[] arr) {
  int gap = 1;
  for(int i = 0 ; i + gap - 1 < arr.length; i += (2 * gap)) {
    int start = i, mid = i + gap - 1, end = i + 2 * gap - 1;
    if(end > arr.length - 1) {
      end = arr.length - 1;
    }
    merge(arr, start, mid, end);
  }
  gap *= 2;
}

最优时间复杂度:O( n log ⁡ 2 n n\log_2 n nlog2n

最坏时间复杂度:O( n log ⁡ 2 n n\log_2 n nlog2n

平均时间复杂度:O( n log ⁡ 2 n n\log_2 n nlog2n

空间复杂度:O(n)

稳定性:稳定

堆排序

将待排序序列构建成一个大顶堆,将最大值(堆顶)和序列最后一个元素交换,然后对于剩余的n-1个序列重新构成一个堆,重复操作。

public static void maxHeapSort(int[] arr) {
  int len = arr.length - 1;
  for(int i = len /2 - 1; i >= 0; i--) {
    maxHeapAdjust(arr, i, len);
  }
  
  for(int i = len; i >= 0; i--) {
    swap(arr, 0, i);
    maxHeapAdjust(arr, 0, i - 1);
  }
}

public static void maxHeapAdjust(int[] arr, int s, int m) {
  int i, temp = arr[s];
  for(i = 2 * s; i <= m; i *= 2) {
    if(arr[i + 1] > arr[i]) {
      ++i;
    }
    if(temp >= arr[i]) {
      break;
    }
    
    arr[s] = arr[i];
    s = i;
  }
  
  arr[s] = temp;
}

最优时间复杂度:O( n log ⁡ 2 n n\log_2 n nlog2n

最坏时间复杂度:O( n log ⁡ 2 n n\log_2 n nlog2n

平均时间复杂度:O( n log ⁡ 2 n n\log_2 n nlog2n

空间复杂度:O(1)

稳定性:不稳定

快速排序

从数列中选取一个基数,将比基数小的放在基数前面,比基数大的摆在基数后面,该分区退出后,该基准就处于数列的中间,递归堆基数前子序列和后序列进行上述操作,完成排序

  1. 递归操作
public static void quickSort(int[] arr, int start, int end) {
  int pivot;
  if(start < end) {
    pivot = Partition(arr, start, end);
    
    Partition(arr, start, pivot - 1);
    Partition(arr, pivot + 1, end);
  }
}

public static void Partition(int[] arr, int start, int end) {
  int pivotkey = arr[start];
  while(start < end) {
    while((start < end) && (arr[end] >= pivotkey)) {
      end--;
    }
    swap(arr, start, end);
    
    while((start < end) && (arr[start] <= pivotkey)) {
      start--;
    }
    swap(arr, start, end);
  }
  
  return low;
}
  1. 非递归操作

用栈来保存边界值(start和end)

public static void quickSortNon(int[] arr) {
  int[] stack = new int[arr.length];
  int top = 0;
  int start = 0;
  int end = arr.length - 1;
  int pivok = Partition(arr, start, end);
  if(pivot > start + 1) {
    stack[top++] = start;
    stack[top++] = pivok - 1;
  }
  if(pivok < end - 1) {
    stack[top++] = pivok + 1;
    stack[top++] = end;
  }
  
  while(top > 0) {
    end = stack[--top];
    start = stack[--top];
    pivok = Partition(arr, start, end);
    if(pivok > start + 1) {
      stack[top++] = start;
      stack[top++] = pivok - 1;
    }
    if(pivok < end - 1) {
      stack[top++] = pivok + 1;
      stack[top++] = end;
    }
  }
}

public static int Partition(int[] arr, int start, int end) {
  int pivokkey = arr[start];
  while(start < end) {
    while((start < end) && (arr[end] >= pivokkey)) {
      end--;
    }
    swap(arr, start, end);
    while((start < end) && (arr[start] <= pivokkey)) {
      start++;
    }
    swap(arr, start, end);
  }
  
  return start;
}

最优时间复杂度:O( n log ⁡ 2 n n\log_2 n nlog2n

最坏时间复杂度:O( n 2 n^2 n2

平均时间复杂度:O( n log ⁡ 2 n n\log_2 n nlog2n

空间复杂度:O(n)

稳定性:不稳定

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值