十大排序算法(Java实现)没入门就放弃

前言
花了将近一天的时间复盘了一下常用的十大排序算法,涉及到的内容也是蛮多的,如果有哪些地方有错误,希望大佬们多多指点指点。
术语解释
这里涉及到了一些名词:时间复杂度、空间复杂度等,那么,这是什么意思?
时间复杂度:执行一个算法所需要的时间。
空间复杂度:运行完一个算法所需要的内存空间。
稳定性:假如a==b,并且未排序时,a在b的前面,排序结束后,a仍在b的前面,那么我们就称之为稳定。反之,我们就称为不稳定。
内排序:所有排序操作都在内存中完成。
外排序:由于数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行。
如何计算时间复杂度?
以冒泡算法为例:数组中含有n个数,共需比较n-1轮,第一轮比较n-1次,第二轮比较n-2次,第三轮比较n-3次,直至排完序,可以看为是一个等差数列,所以共比较1/2n^2-1/2n,根据复杂度的规则,去掉低阶项,去掉常数系数,所以时间复杂度就是O(n2)。
如何计算空间复杂度?

算法性质
在这里插入图片描述
一、冒泡排序
1.1、算法描述:
将第一个元素与第二个元素进行比较,如果第一个大于第二个,则交换位置,后面每两个相邻的元素做同样的操作,谁大谁就放到后面,第一轮比较完毕后,可以得到最大的。
此时除去最右边最大的元素,将剩下的元素重复上面的步骤直至排序完成。
1.2、代码实现
我这里直接将算法采用个例子实现了,方便观察运行结果,原理是都一样的。

package com.hpu.edu.dong;

public class BubbleSort {
	/*冒泡排序*/
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int arr[]={1,5,3,2,9,6,4,7,8};
		//总共比较的圈数
		for (int i = 0; i < arr.length-1; i++) {
			//每圈内比较的次数
			for (int j = 0; j < arr.length-1-i; j++) {
				//如果前面的数大于后面的数,则交换两个数的位置
				if(arr[j]>arr[j+1]){
					int a=arr[j];
					arr[j]=arr[j+1];
					arr[j+1]=a;
				}
			}
		}
		//打印
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i]+" ");
		}
	}

}

二、选择排序
2.1、算法描述
首先在数组中搜索一遍,找到最小的元素,让其与第一个元素进行交换,我们令最小的元素为有序区,后面的为无序区。第二轮排序,找到最小的元素,让它与无序区的第一个元素进行交换。依次类推,完成数组的排序。
但是需要注意的是,在寻找最小值的过程中,只是交换了元素之间的坐标,还没有交换值,等此轮比较完成之后,再依据坐标完成值的交换。这一点和冒泡排序是不同的。冒泡排序是比较完之后立马交换值,而选择排序则是先交换坐标,本轮比较完成之后,再交换值。
2.2、代码实现

package com.hpu.edu.dong;

public class SelectionSort {
	/*选择排序*/
	//选择排序和冒泡排序的区别:冒泡排序比较完数值之后,立马交换位置,
	//而选择排序则是交换了数值所在的位置,等到比较完之后,再交换数值,在一定程度上减少了数值交换的次数
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int arr[]={1,5,9,3,7,4,2,6,8};
		for (int i = 0; i < arr.length; i++) {
			int minindex=i;
			for (int j = i; j < arr.length; j++) {
				if(arr[minindex]>arr[j]){
					minindex=j;
				}
			}
			if(minindex!=i){
				int a=arr[minindex];
				arr[minindex]=arr[i];
				arr[i]=a;
			}
		}
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i]+" ");
		}
	}

}

三、插入排序
3.1、算法描述
选取数组第二个元素,令第一个元素为有序数组。从第二个元素开始为无序数组。将第二个元素与有序数组的元素进行比较,如果大于有序数组中的元素,则放在有序数组中的元素的后面,如果小于,则放在前面。此时有序数组大小增大为两个。继续令无序数组第一个元素与有序数组中的元素进行比较,直至排序完毕。
3.2、代码实现

package com.hpu.edu.dong;

public class InsertSort {
	//插入排序:将一个数组分为未排序和已排序两个数组,令第一个数为已排序,第二个数为未排序的第一个数,
	//让他们进行比较,并依次类推
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int arr[]={1,5,9,3,7,4,2,8,6};
		for (int i = 1; i < arr.length; i++) {
			int temp=arr[i];//未排序的第一个数
			int a=i-1;//已排序的最后一个数的位置
			while(a>=0&&arr[a]>temp){
				arr[a+1]=arr[a];
				a--;
			}
			arr[a+1]=temp;
		}
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i]+" ");
		}
	}

}

四、希尔排序
4.1、算法描述
希尔排序可以说是插入排序的一种。那么,希尔排序是什么呢?
我们假定一个数组有六个元素,长度为8。第一次我们将其各元素间隔为8/2=4,即a[0]与a[4]、a[1]与a[5]、a[2]与a[6]、a[3]与a[7]。每组采用插入排序的算法进行排序。然后再将各元素划分为间隔4/2=2。并按照之前的步骤进行排序。当间隔为1时,此时数组各元素已经不是太无序了。再进行简单的排序即可。
4.2、代码实现

package com.hpu.edu.dong;

public class ShellSort {
	//希尔排序
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int arr[]={1,3,5,7,9};
		int a=arr.length;
		int half=a/2;
		while(half>0){
			for (int i = half; i < arr.length; i++) {
				int temp=arr[i];
				int pindex=i-half;
				while(pindex>=0&&arr[pindex]>temp){
					arr[pindex+half]=arr[pindex];
					pindex-=half;
				}
				arr[pindex+half]=temp;
			}
			half/=2;
		}
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i]+" ");
		}
		
	}
}

五、归并排序
5.1、算法描述
归并排序是建立在归并操作的一种高效的排序方法,该方法采用了分治的思想。
通过递归的方式将大的数组分割为两个,并不断分割,直至每个组划分为只有一个元素。此时每个数组只有一个元素,我们可以认为是有序的。然后再将这两个元素进行排序合并为两个元素大小的数组,并不断重复此步骤,合并为大小为四个、八个。直至大小为原先的数组。
5.2、代码实现

package com.hpu.edu.dong;

public class MergeSort {
	//归并排序
	public static void main(String[] args){
		int arr[]={5,4,3,2,1};
		int temp[]=new int[arr.length];//新建一个临时数组存放
		mergeSort(arr,0,arr.length-1,temp);
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i]+" ");
		}
	}
	public static void merge(int arr[],int low,int mid,int high,int temp[]){
		int i=0;
		int j=low,k=mid+1;//左边序列和右边序列起始索引
		while(j<=mid&&k<=high){
			if(arr[j]<arr[k]){
				temp[i++]=arr[j++];
			}else{
				temp[i++]=arr[k++];
			}
		}
		//若左边序列还有剩余,则将其全部拷贝进temp[]中
		while(j<=mid){
			temp[i++]=arr[j++];
		}
		while(k<=high){
			temp[i++]=arr[k++];
		}
		for(int t=0;t<i;t++){
			arr[t+low]=temp[t];
		}
	}
	public static void mergeSort(int arr[],int low,int high,int temp[]){
		if(low<high){
			int mid=(high+low)/2;
			mergeSort(arr,low,mid,temp);//对左边序列进行归并排序
			mergeSort(arr,mid+1,high,temp);//对右边序列进行归并排序
			merge(arr,low,mid,high,temp);//合并两个有序序列
		}
	}
}

六、快速排序
6.1、算法描述
从数组中选取一个元素,让它为中轴元素,让数组中的元素和它进行对比,数组中比他小的元素放在左边,比它大的元素放在右边。这样一个数组就分为两个数组,并且中轴元素的位置是确定不会改变的。对左右两边的数组分别进行同样的操作直至完成数组的排序。
6.2、代码实现

package com.hpu.edu.dong;

import java.util.Arrays;

public class QuickSort {
	//快速排序
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int arr[]={5,3,1,7,9};
		quickSort(arr,0,arr.length-1);
		System.out.println(Arrays.toString(arr));
		
	}
	public static void quickSort(int arr[],int low,int high){
		//递归出口
		if(low>high){
			return ;
		}
		//标记
		int i=low;
		int j=high;
		int key=arr[low];
		//完成一趟快排
		while(i<j){
			while(i<j&&arr[j]>key){
				j--;
			}
			while(i<j&&arr[i]<=key){
				i++;
			}
			if(i<j){
				int temp=arr[j];
				arr[j]=arr[i];
				arr[i]=temp;
			}
			//调整key的位置
			arr[low]=arr[i];
			arr[i]=key;
			//对key左边的数快排
			quickSort(arr,low,i-1);
			//对key右边的数快排
			quickSort(arr,i+1,high);
		}
	}
}

七、堆排序
7.1、算法描述
堆的特点就是堆的顶的元素是个最值,大顶堆的堆顶是最大值,小顶堆的堆顶是最小值。
堆排序就是将堆顶的元素和最后一个元素交换位置,交换完成之后破坏了堆的特性。将堆中剩余的元素再次构成一个大顶堆。然后将剩余的大顶堆和最后一个元素交换位置,重复之前的操作,即可完成排序。
7.2、代码实现

package com.hpu.edu.dong;

public class HeapSort {
    // 堆排序
    public static int[] headSort(int[] arr) {
        int n = arr.length;
        //构建大顶堆
        for (int i = (n - 2) / 2; i >= 0; i--) {
            downAdjust(arr, i, n - 1);
        }
        //进行堆排序
        for (int i = n - 1; i >= 1; i--) {
            // 把堆顶元素与最后一个元素交换
            int temp = arr[i];
            arr[i] = arr[0];
            arr[0] = temp;
            // 把打乱的堆进行调整,恢复堆的特性
            downAdjust(arr, 0, i - 1);
        }
        return arr;
    }

        //下沉操作
    public static void downAdjust(int[] arr, int parent, int n) {
        //临时保存要下沉的元素
        int temp = arr[parent];
        //定位左孩子节点的位置
        int child = 2 * parent + 1;
        //开始下沉
        while (child <= n) {
            // 如果右孩子节点比左孩子大,则定位到右孩子
            if(child + 1 <= n && arr[child] < arr[child + 1]){
            	child++;
            }
                
            // 如果孩子节点小于或等于父节点,则下沉结束
            if (arr[child] <= temp ) 
            	break;
            // 父节点进行下沉
            arr[parent] = arr[child];
            parent = child;
            child = 2 * parent + 1;
        }
        arr[parent] = temp;
    }
}

八、计数排序
8.1、算法描述
额外创建一个数组,统计原先数组中各个元素出现的次数,最后将临时数组中的元素按照顺序从小到大进行排序。
8.2、代码实现

package com.hpu.edu.dong;

public class CountSort {
	//计数排序
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int arr[]={3,5,4,4,6,9};
		int max=arr[0];
		for (int i = 0; i < arr.length; i++) {
			if(max<arr[i]){
				max=arr[i];
			}
		}
		int temp[]=new int[max+1];
		for (int i = 0; i < arr.length; i++) {
			temp[arr[i]]++;
		}
		int k=0;
		for (int i = 0; i <= max; i++) {
			for(int j=temp[i];j>0;j--){
				arr[k++]=i;
			}
		}
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i]+" ");
		}
	}

}

九、桶排序
9.1、算法描述
桶排序将最大值与最小值之间的数进行划分为多个区间,每个区间可以认为是一个桶,然后将每个区间对应的数分别放进每个桶中,然后对每个桶中的元素进行排序,归并、快排都是可以的。
9.2、代码实现

package com.hpu.edu.dong;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;

public class BucketSort {
	//桶排序
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//定义数组
		int arr[]={2,1,2,1,3,6,5,4};
		//定义最小值
		int min=arr[0];
		//定义最大值
		int max=arr[0];
		//获取数组中的最大值与最小值
		for (int i = 0; i < arr.length; i++) {
			if(min>arr[i]){
				min=arr[i];
			}
			if(max<arr[i]){
				max=arr[i];
			}
		}
		//定义桶数
		int d=max-min;
		int bucketNum=d/5+1;
		ArrayList<LinkedList<Integer>> bucketList=new ArrayList<>(bucketNum);
		//初始化桶
		for (int i = 0; i < bucketNum; i++) {
			bucketList.add(new LinkedList<Integer>());
		}
		//向各个桶中添加元素
		for (int i = 0; i < arr.length; i++) {
			bucketList.get((arr[i]-min)/d).add(arr[i]-min);
		}
		//各个桶中进行排序
		for (int i = 0; i < bucketNum; i++) {
			Collections.sort(bucketList.get(i));
		}
		//将各个桶中的元素返回给原数组
		int k=0;
		for (int i = 0; i < bucketNum; i++) {
			for (Integer t : bucketList.get(i)) {
				arr[k++]=t+min;
			}
		}
		//打印数组中的元素
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i]+" ");
		}
	}
}

十、基数排序
10.1、算法描述
先以个位数的大小来进行排序,然后将数返回,再以十位数大小来进行排序,再以百位数的大小来进行排序。排到最后就是一个完整有序的数组了。
10.2、代码实现

package com.hpu.edu.dong;

import java.util.ArrayList;
import java.util.LinkedList;

public class RadioSort {
	//基数排序
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int arr[]={2,6,11,54,32,66,22,71};
		int n=arr.length;
		int max=arr[0];
		//找出最大值
		for (int i = 0; i < arr.length; i++) {
			if(max<arr[i]){
				max=arr[i];
			}
		}
		//计算最大值是几位数
		int num=1;
		while(max/10>0){
			num++;
			max=max/10;
		}
		//创建10个桶
		ArrayList<LinkedList<Integer>> bucketList=new ArrayList<>(10);
		//初始化桶
		for(int i=0;i<10;i++){
			bucketList.add(new LinkedList<Integer>());
		}
		//进行每一趟的排序,从个位数开始排
		for(int i=1;i<=num;i++){
			for(int j=0;j<n;j++){
				//获取每个数最后第i位是数组
				int radio=(arr[j]/(int)Math.pow(10, i-1))%10;
				//放进对应的桶里
				bucketList.get(radio).add(arr[j]);
			}
			//合并放回原数组
			int k=0;
			for(int j=0;j<10;j++){
				for(Integer t:bucketList.get(j)){
					arr[k++]=t;
				}
				//取出来合并之后把桶清光数据
				bucketList.get(j).clear();
			}
			
		}
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i]+" ");
		}
		
		
	}

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值