package com.algorithm;
import java.util.Random;
/**
* 八种常见排序算法:插入、冒泡、选择、希尔、归并、快排、堆排序、基数排序
* @author Wennian
*
*/
public class Sort {
public static void main(String[] args) {
// TODO Auto-generated method stub
// 构建初始化乱序数组,采用随机数的方式,生成整数(正数、0、负数)
int N = 100;
int[] arr = new int[N];
for(int i=0;i<N;i++){
// 随机生成0-N-1的数,其中1/10的数为负数
arr[i] = new Random().nextInt(N) - N/10;
}
Sort sort = new Sort();
//sort.BubbleSort(arr);
//sort.InserSort(arr);
//sort.SelectSort(arr);
//sort.SheelSort(arr);
//sort.QuickSort(arr);
//sort.mergeSort(arr);
sort.heapSort(arr);
for(int i=0;i<N;i++){
System.out.print(arr[i]+" ");
if(i%10 == 0 && i>0){
System.out.println();
}
}
}
/**
* 冒泡排序:一组数,每次把最大的数往后沉
* 时间复杂度:o(n^2) 空间复杂度:o(1)
* 稳定
*/
void BubbleSort(int[] arr){
int len = arr.length;
int end = len-1; // 初始时,结束位置为数组末尾
int start = 0; // 每次从第一个元素开始往后遍历
// 一共需要len趟才能排序完成
for(int i=0;i<len;i++){
start = 0;
while(start < end){
if(arr[start]>arr[start+1]){
arr[start] ^= arr[start+1];
arr[start+1] ^= arr[start];
arr[start] ^= arr[start+1];
}
start++;
}
end--; //每趟排序之后,待排数组长度减1
}
}
/**
* 插入排序:认为前面的数组已经有序,每次向原来的数组中插入一个数
* 时间复杂度o(n^2) 空间复杂度o(1)
* 稳定
* @param arr
*/
void InserSort(int[] arr){
int len = arr.length;
int end = 0; // 已经排序好的数组
int start = end+1; // 下一个要插入的元素
while(start<=len-1){
for(int i = end;i>=0;i--){
if(arr[i+1]<arr[i]){
arr[i+1] ^= arr[i];
arr[i] ^= arr[i+1];
arr[i+1] ^= arr[i];
}else{
break;
}
}
end = start;
start++;
}
}
/**
* 选择排序:有序区和无序区,有序区的元素小于无序区,每次选择无需去的最小元素放在有序区后面
* 时间复杂度o(n^2) 空间复杂度o(1)
* 稳定
*/
void SelectSort(int[] arr){
int len = arr.length;
int start = 0; // 无序区的第一个元素,认为他是最小值
while(start < len){
for(int i=start+1;i<len;i++){
if(arr[start]>arr[i]){
arr[start] ^= arr[i];
arr[i] ^= arr[start];
arr[start] ^= arr[i];
}
}
start++;
}
}
/**
* 希尔排序:缩小增量排序,每次缩小增量gap,间隔gap的数为一个子序列,
* 依次缩小增量,直到gap=1,对每个子序列采用直接选择排序
* 时间复杂度o(nlogn)~o(n^2) 空间复杂度 o(1)
* 不稳定
*/
void SheelSort(int[] arr){
int len = arr.length;
// gap选择为奇数,gap的选择直接影响排序的效率
// 若选择偶数,gap=4会重复gap=8的排序比较,时间浪费
for(int gap=len/2+1;gap>0;gap/=2){
//对子序列进行直接选择排序,一共有gap个子序列
for(int subarr=0;subarr<gap;subarr++){
int start = subarr;
// 直接选择排序
while(start<len){
for(int i=start+gap;i<len;i+=gap){
if(arr[start]>arr[i]){
arr[start] ^= arr[i];
arr[i] ^= arr[start];
arr[start] ^= arr[i];
}
}
start +=gap;
}
}
}
}
/**
* 快序排序:每次找到一个分割值,满足:左边<=分割值<=右边,重复此过程直到有序
* 时间复杂度o(nlogn) 空间复杂度o(1)
* 不稳定
* @param arr
*/
void QuickSort(int[] arr){
int len =arr.length;
int left = 0 ;
int right = len-1;
quickSort(arr,left,right);
}
void quickSort(int[] arr ,int left,int right){
if(left < right){
int split = arr[left];
int index1 = left, index2 = right;
while(index1<index2){
while(arr[index2]>=split && index1<index2){
index2--;
}
if(index1<index2)
arr[index1++] = arr[index2];
while(arr[index1]<=split && index1<index2){
index1++;
}
if(index1<index2)
arr[index2--] = arr[index1];
}
arr[index1] = split;
// 递归调用
quickSort(arr,left,index1);
quickSort(arr,index1+1,right);
}
}
/**
* 归并排序:将数组分为子数组,认为每一个子数组已经有序,对两个有序数组进行归并
* 时间复杂度o(nlogn) 空间复杂度o(n)
* 稳定
*/
void mergeSort(int[] arr){
int len = arr.length;
if(len<=0)
return;
divideArray(arr,0,len-1);
}
void divideArray(int[] arr,int left,int right){
if(left < right){
int mid = left + (right - left)/2;
// 分解
divideArray(arr,left,mid);
divideArray(arr,mid+1,right);
// 合并
mergeArray(arr,left,mid,right);
}
}
void mergeArray(int[] arr,int left,int mid,int right){
// 合并两个有序子数组arr[left..mid] arr[mid+1..right]
int i=left,m=mid,j=mid+1,n=right;
int[] tmp = new int[right-left+1];
int k=0;
while(i<=m && j<=n){
if(arr[i]<=arr[j])
tmp[k++] = arr[i++];
else
tmp[k++] = arr[j++];
}
while(i<=m)
tmp[k++] = arr[i++];
while(j<=n)
tmp[k++] = arr[j++];
// copy tmp to arr
for(int t=0;t<k;t++)
arr[left+t] = tmp[t];
}
/**
* 堆排序:大根堆,每次取堆顶元素,将堆顶元素与最后一个值交换,然后调整堆依次
* 整个过程相当于一个不断建堆的过程
* 时间复杂度o(nlogn) 空间复杂度o(1)
* 不稳定
*/
void heapSort(int[] arr){
// 将初始数组看做已经建好的堆,调整堆
// parent:i child:2i+1 2i+2
// 从第一个非叶子节点往上调整
int len = arr.length;
int last = len-1;
while(last >= 0){
// 调整堆,将最大值放在堆顶,即第一个元素
for(int p=(last-1)/2;p>=0;p--){
int cur = p;
// 只有第一次需要建立堆,其他时候只要从根节点开始调整堆即可
if(last != len-1){
cur = 0;
p = 0;
}
while(cur <= (last-1)/2){
int child = 2*cur+1;
if(child<last-1 && arr[child] < arr[child+1])
child += 1;
if(arr[cur] < arr[child]){
arr[cur] ^= arr[child];
arr[child] ^= arr[cur];
arr[cur] ^= arr[child];
}
cur = child;
}
}
// 交换堆顶元素和最后一个元素
if(arr[0] != arr[last]){
arr[last] ^= arr[0];
arr[0] ^= arr[last];
arr[last] ^= arr[0];
}
last--;
}
}
}
八种常见排序算法:插入、冒泡、选择、希尔、归并、快排、堆排序、基数排序
最新推荐文章于 2022-04-26 15:36:02 发布