package com.wschase.sort;
import java.util.Stack;
/**7种排序算法
* Author:WSChase
* Created:2019/4/12
*/
public class Solution {
//在进行下面的排序算法之前我们先写一下数组打印的方法方便后面的测试
public void printArray(int[] array,int size){
for(int i=0;i<size;i++){
System.out.println(array[i]);
}
}
/**
* 1.直接插入排序
* 最坏时间复杂度:O(n^2)
* 最好时间复杂度:O(n)
* 空间复杂度:O(1)
* 稳定性:稳定
*/
public void insertintoSort(int[] array,int size){
//直接插入排序最重要的就是要知道我们每次进行的是从后面往前面进行插入
//前面的已经是有序的了,所以我们插入的数据只需要往前比较一个就可以。
for(int i=1;i<size;i++){//i从1开始是因为,如果第一个数插入的是下标为0的数那么这个数就不需要
//进行比较,直接进行插入就可以了。
int temp=array[i];
int j;
for(j=i-1;j>=0;j--){
if(array[j]<=temp){
//如果前面的数比插入的数小,那么我们不需要做操作,直接进行插入就可以
break;
}
//否则将前面较大的数挪到后面,然后将需要插入的数插入到j这个位置
array[j+1]=array[j];
}
//因为前面的j一直处于循环在改变,所以最后这个j不满足条件的时候是在空格的前一个位置
//而我们需要插入的位置是在空格位置,所以我们需要将j+1才可以进行赋值。
array[j+1]=temp;
}
}
/**
* 2.归并排序
* 最坏时间复杂度:O(n*log(n))
* 最好时间复杂度:O(n*log(n))
* 空间复杂度:O(n)
* 稳定性:稳定
*/
//实现归并排序
public void _megerSort(int[] array,int left,int right){
//递归的终止条件:如果里面只有一个元素或者没有元素了那么就不需要进行排序了
if(right<=left+1){
return;
}
//如果不满足那么将区间分为两个区间
int mid=left+(right-left)/2;
_megerSort(array,left,mid);
_megerSort(array,mid,right);
//当我们经过上面的排序以后就已经将一个数组排序为左右两边都是有序的了,所以我们直接将它们进行合并即可
meger(array,left,mid,right);
}
//合并两个有序的数组
public void meger(int[] arrray,int left,int mid,int right){
//首先我们要想清楚的是在合并的时候我们需要一个额外的数组空间将已经排序号的数组进行存放
int size=right-left;
int[] extra=new int[size];
int left_index=left;
int right_index=mid;
int extra_index=0;
//这两个区间是:[left,mid),[mid,right)
while (left_index<mid&&right_index<right){
if(arrray[left_index]<=arrray[right_index]){
extra[extra_index]=arrray[left_index];
left_index++;
}else {
extra[extra_index]=arrray[right_index];
right_index++;
}
//不管是哪种情况,它的下标都需要进行加1操作
extra_index++;
}
while (left_index<mid){
//如果只有一个条件满足,那么就直接将数组拷贝过去
extra[extra_index++]=arrray[left_index++];
}
while (right_index<right){
extra[extra_index++]=arrray[right_index++];
}
//然后将排好序的数组再拷贝回去
for(int i=0;i<size;i++){
arrray[left+i]=extra[i];
}
}
//实现归并排序
public void megeSort(int[] arrray,int size){
//这是一个左闭右开的区间
_megerSort(arrray,0,size);
}
/**
* 3.快速排序
* 最好时间复杂度:
* 最坏时间复杂度:
* 空间复杂度:
* 稳定性:
*/
public static void quickSort(int[] arr,int low,int high){
int i,j,temp;
if(low>high){
return;
}
i=low;//左边哨兵的索引
j=high;//右边哨兵的索引
//temp就是基准位
temp = arr[low];//以最左边为 基准位
while (i<j) {
//先看右边,依次往左递减
//先从右往左找一个小于 基准位的数
//当右边的哨兵位置所在的数>基准位的数 时
//继续从右往左找(同时 j 索引-1)
//找到后会跳出 while循环
while (temp<=arr[j]&&i<j) {
j--;
}
//再看左边,依次往右递增
//步骤和上面类似
while (temp>=arr[i]&&i<j) {
i++;
}
//如果满足条件则交换
if (i<j) {
//z、y 都是临时参数,用于存放 左右哨兵 所在位置的数据
int z = arr[i];
int y = arr[j];
//左右哨兵 交换数据(互相持有对方的数据)
arr[i] = y;
arr[j] = z;
}
}
//这时 跳出了 “while (i<j) {}” 循环
//说明 i=j 左右在同一位置
//最后将基准为与i和j相等位置的数字交换
arr[low] = arr[i];//或 arr[low] = arr[j];
arr[i] = temp;//或 arr[j] = temp;
//i=j
//这时左半数组<(i或j所在索引的数)<右半数组
//也就是说(i或j所在索引的数)已经确定排序位置, 所以就不用再排序了,
// 只要用相同的方法 分别处理 左右数组就可以了
// 递归调用左半数组
quickSort(arr, low, j-1);
//递归调用右半数组
quickSort(arr, j+1, high);
}
//真正调用快速排序方法
public void quickSort1(int[] array,int size){
quickSort(array,0,size-1);
}
/**
* 4.冒泡排序
* 最好时间复杂度:O(n)
* 最坏时间复杂度:O(n^2)
* 空间复杂度:O(1)
* 稳定性:稳定
*/
public void bubbleSort(int[] array,int size){
//这个是用来标记冒泡排序是否需要进行
for(int i=1;i<size;i++){//这个i表示一共需要进行多少趟的排序
int sorted=1;
for(int j=0;j<size-1;j++){//这个j表示进行一趟的排序需要进行多少次
if(array[j]>array[j+1]){
//做这个交换过程是为了让小数排在前面,大数排在后面
int temp=array[j];
array[j]=array[j+1];
array[j+1]=temp;
sorted=0;
}
}
if(sorted==1){//表示没有经过上面的交换过程
break;
}
}
}
/**
* 5.选择排序
*
*/
public void selectSort(int[] array,int size){
for(int i=1;i<size;i++){
//我们暂且选下标3作为最大值的数组元素的下标
int max=0;
for(int j=0;j<=size-i;j++){
if(array[j]>array[max]){//将数组中的元素从前到后一次遍历与最大值进行比较
max=j;
}
}
//进行完一轮最大值的筛选之后就将最大值赋值到数组的最后面:每次的最后面是size-i这个数组下标对应的值
int temp=array[size-i];
array[size-i]=array[max];//进行完一轮比较之后将最大值放在数组最后面
array[max]=temp;
}
}
/**
* 6.希尔排序:希尔排序就是直接排序的升级版
*/
//首先我们将间隔排序写出来
public void insertWihGapSort(int[] array,int size,int gap){
//间隔排序就是将直接排序的起点改为间隔
for(int i=gap;i<size;i++){
int k=array[i];//这个表示需要插入的数
int j;
//将需要插入的数和前面间隔为gap的数进行比较
for(j=i-gap;j>=0;j-=gap){
if(array[j]<=k){
//如果前面的数比要插入的数小,就不需要管
break;
}
//否则将前面的数往后移动
array[j+gap]=array[j];
}
//经过这一轮比较之后需要将要插入的数插入到对应的位置
array[j+gap]=k;
}
}
//下面再进行希尔排序
public void shellSort(int[] array,int size){
int gap=size;
while (true){
gap=(gap/3)+1;
insertWihGapSort(array,size,gap);
if(gap==1){
break;
}
}
}
/**
* 7.堆排序
*/
public static void heapSort(int []arr){
//1.构建大顶堆
for(int i=arr.length/2-1;i>=0;i--){
//从第一个非叶子结点从下至上,从右至左调整结构
adjustHeap(arr,i,arr.length);
}
//2.调整堆结构+交换堆顶元素与末尾元素
for(int j=arr.length-1;j>0;j--){
swap(arr,0,j);//将堆顶元素与末尾元素进行交换
adjustHeap(arr,0,j);//重新对堆进行调整
}
}
/**
* 调整大顶堆(仅是调整过程,建立在大顶堆已构建的基础上)
* @param arr
* @param i
* @param length
*/
public static void adjustHeap(int []arr,int i,int length){
int temp = arr[i];//先取出当前元素i
for(int k=i*2+1;k<length;k=k*2+1){//从i结点的左子结点开始,也就是2i+1处开始
if(k+1<length && arr[k]<arr[k+1]){//如果左子结点小于右子结点,k指向右子结点
k++;
}
if(arr[k] >temp){//如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
arr[i] = arr[k];
i = k;
}else{
break;
}
}
arr[i] = temp;//将temp值放到最终的位置
}
/**
* 交换元素
* @param arr
* @param a
* @param b
*/
public static void swap(int []arr,int a ,int b){
int temp=arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
Solution s=new Solution();
int[] array=new int[]{1,5,9,3,2,8,7,3};
//(1)直接插入排序
// s.insertintoSort(array,array.length) ;
//(2)归并排序
// s.megeSort(array,array.length);
//(3)快速排序
s.quickSort1(array,array.length);
//(4)冒泡排序
// s.bubbleSort(array,array.length);
//(5)选择排序
// s.selectSort(array,array.length);
//(6)希尔排序
// s.shellSort(array,array.length);
//(7)堆排序
// s.heapSort(array);
s.printArray(array,array.length);
}
}
7中常见排序算法
猜你喜欢
转载自blog.csdn.net/ZhuiZhuDream5/article/details/89261975
今日推荐
周排行