1、选择、插入、冒泡
import java.util.Arrays;
import java.util.Collections;
import java.util.Scanner;
import java.util.Stack;
class Sort{
public static int[] swap(int[]nums,int i, int j){
int temp;
temp = nums[j];
nums[j] = nums[i];
nums[i] = temp;
return nums;
}
//选择排序
public static void SelectS(int[] nums) {
int minNum;
for (int i = 0;i < nums.length; i++){
minNum = i;
for(int j = i+1;j < nums.length; j++){
if( nums[minNum] > nums[j]){
minNum = j;
}
}
swap(nums,i,minNum);
}
System.out.println( Arrays.toString(nums));
}
//冒泡排序
public static void MaoPaoS(int[] nums){
int maxNum,N;
N = nums.length;
boolean hasSort = true; //在一轮循环中,如果没有发生交换,就说明数组已经是有序的,此时可以直接退出。
for(int i = N - 1; i > 0 && hasSort;i--){
hasSort = false;
for(int j = 0; j < nums.length-1 ;j++){
if(nums[j] > nums[j+1]){
hasSort = true;
swap(nums,j,j+1);
}
}
}
System.out.println( Arrays.toString(nums)); //[1, 2, 3, 4, 5, 6]
}
//插入排序
public static void InsertS(int[] nums){
int N;
N = nums.length;
for (int i = 1;i < N; i++){ //与当前位置的前面所有位置的数进行比较,小于,则调换
for(int j = i;j > 0 && (nums[j-1]> nums[j]); j--){
swap(nums,j,j-1);
}
}
System.out.println( Arrays.toString(nums));
}
//
}
2、归并
//自顶向下的归并排序
class Merge{
/*
* 分治的思想,将数组分为两个子数组,分别排序,再合并为一个
* 时间复杂度:NlogN
* */
private static int[] aux;
private static void merge(int[] nums,int lo, int mid, int hi){
int i = lo, j = mid + 1;
int[] auk = new int[ hi + 1 ];
for( int k = lo; k <= hi; k++){ //copy
auk[k] = nums[k];
}
for(int k = lo; k <= hi; k++){
if( i > mid ) //左边用尽,取右边得元素
nums[k] = auk[j++];
else if( j > hi ) //右边用尽,取左边得元素
nums[k] = auk[i++];
else if(auk[i] < auk[j]) // 右半边得当前元素小于左半边得当前元素(取右半边的元素)
nums[k] = auk[j++];
else
nums[k] = auk[i++];
}
}
private static void mergeSort(int[] nums,int lo, int hi){
if(hi <= lo)
return;
int mid = lo + (hi - lo)/2;
mergeSort(nums, lo, mid); //将左边排序
mergeSort(nums,mid+1,hi); //右边排序
merge(nums, lo, mid, hi); //归并
}
public static void mergeSort(int[] nums){
mergeSort(nums, 0, nums.length-1);
System.out.println( Arrays.toString(nums)); // [6, 5, 4, 3, 2, 1]
}
}
3、快排
【主要思想】:将待排序数组以某一个元素为阈值分为两个子列,一个子列包含所有比改阈值小的元素,另一个子列反之。这样只要将这两个子列排好序,整个数组也就排好序了。这里有一个关键的子过程就是划分的过程Partition,一般可以选择数组中任意的元素作为划分阈值,这里选择的是数组中最右端的元素。
【Partition】:使用了二分查找类似的思想:使用两个索引器从数组的两端进行遍历,左边的索引器遇到比阈值大的元素停止,右边的索引器遇到比自己小的元素停止,然后交换这两个元素,依次循环。这样数组就划分为了比该阈值大和小(含等于)两个子列了。
//快排
class Quick{
public static void qSort(int[] nums){
// Collections.shuffle(nums);
quickSort(nums, 0, nums.length-1);
System.out.println( Arrays.toString(nums)); //[6, 5, 4, 3, 2, 1]
}
private static void quickSort(int[] nums, int lo, int hi) {
if(hi < lo) return;
int j = partition(nums, lo, hi); //切分
quickSort(nums, lo, j-1); //左排
quickSort(nums, j+1, hi); // 右排
}
// 找切分点
private static int partition(int[] nums, int lo, int hi) {
int i = lo,j = hi+1;
int v = nums[lo];
while(true) {
while (nums[++i] > v) {
if (i == hi) break;
}
while (nums[--j] < v) {
if (j == lo) break;
}
if (i >= j) break;
swap(nums, i, j);
}
swap(nums, lo, j);
return j;
}
public static int[] swap(int[]nums,int i, int j){
int temp;
temp = nums[j];
nums[j] = nums[i];
nums[i] = temp;
return nums;
}
}
4、堆排序
思想:一个一个的插入,上浮,建最大堆;输出时,将第一个数与末尾的数交换位置,删除最后一个数(即最大值),第一个数再执行下沉的操作;再交换,再删除,输出整个排序序列;
public static void swim(int k){
/*
* 上浮:和父节点比较,大于父节点,就交换,上浮
* */
while( k > 1 && (pq[k/2] < pq[k])){
swap(pq,k/2, k);
k = k/2;
}
}
public static void sink(int k){
/*
* 下沉:某结点比它的两子节点中最大的还小,就交换,下沉
* */
int N = pq.length;
while(2*k < N){
int j = 2*k;
if(j < N && (pq[j] < pq[j+1]))
j += 1;
if(!(pq[k] < pq[j]))
break;
swap(pq, k, j);
k = j;
}
}