java实现各种排序算法

1.冒泡排序:就像冒泡一样,每次将本趟最大的那个数“浮”到数组最末。
时间复杂度为O(N^2)
原理:n个数需要跑n-1趟就可以排好序,n-1个数都放好了之后最后一个数顺序也正确了。
(1)第一层循环控制趟数
(2)第二层循环控制本趟需要两两相互比较的元素个数;每跑一趟,两两相互比较的个数少一。

public class 简单排序 {
public static void main(String[] args) {
	int []a= {5,0,12,3,6,45,1};
	BubbleSort(a);
}
//冒泡排序
private static void BubbleSort(int[] a) {
	// TODO Auto-generated method stub
	for(int i=0;i<a.length-1;i++)//需要跑的趟数,n个数跑n-1趟就行,每趟的目的就是把当前最大的数放到最后
	{
		for(int j=0;j<(a.length-i-1);j++)//本趟需要两两比较的元素个数
		{
			if(a[j]>a[j+1])
			{
				int term=a[j];
				a[j]=a[j+1];
				a[j+1]=term;
			}
		}
	}
	System.out.println("冒泡排序结果");
	for(int i=0;i<a.length;i++)
	{
		System.out.print(a[i]+" ");
	}
}
}

在这里插入图片描述
2.选择排序:每次选择当前最小的数,放到顺序数组中。
时间复杂度为O(N^2)
原理:从数组第0个元素开始,选定第0个元素为本趟最小的数,然后从数组中第1个数开始比较,有比它还小的数就交换。跑完第一趟下来,数组中第0个元素即为数组最小的元素。依此类推,跑n-1趟就可以使数组顺序排列。
(1)第一层循环,i控制的是选定a[i]为本趟最小的数
(2)第二层循环,控制从选定值之后要比较的个数

public class 简单排序2 {
public static void main(String[] args) {
	int []a= {3,5,0,1,2,9};
	SelectSort(a);
}
//选择排序
private static void SelectSort(int[] a) {
	// TODO Auto-generated method stub
	for(int i=0;i<a.length-1;i++)//选定此时数组下标为i的位置为最小的数
	{
		for(int j=i+1;j<a.length;j++)//从选定值的下一位开始比较,直到数组最末
		{
			if(a[j]<a[i])//有比他还小的数,就和他换
			{
				int term=a[i];
				a[i]=a[j];
				a[j]=term;
			}
		}
	}
	System.out.println("选择排序");
	for(int i=0;i<a.length;i++)
	{
		System.out.print(a[i]+" ");
	}
}
}

在这里插入图片描述
3.简单插入排序:在前面序列有序的情况下,将本次的数放到前面有序数列的合适位置。
时间复杂度为O(N^2)
原理:选定一个数,与前面的有序数列从后往前依次比较,放到合适的位置(选定x,之后,与a[i]…a[0]依次比较,如果比x大就后移,x前移)
(1)第一层循环控制选定第i+1个数
(2)第二层循环控制与前面的有序序列(第i个到第0个)依次比较

public class 简单排序3 {
public static void main(String[] args) {
	int []a= {9,0,12,3,6,22};
	SimpleInsertSort(a);
}
//简单插入排序
private static void SimpleInsertSort(int[] a) {
	// TODO Auto-generated method stub
	for(int i=0;i<a.length-1;i++)
	{
		int x=a[i+1];
		for(int j=i;j>=0;j--)
		{
			if(x<a[j])
			{
				a[j+1]=a[j];
				a[j]=x;
			}
		}
	}
	System.out.println("简单插入排序");
	for(int i=0;i<a.length;i++)
	{
		System.out.print(a[i]+" ");
	}
}
}

在这里插入图片描述
4.快速排序:利用分治的思想,确定一个主元将一堆数分成两波,将主元放到数组中合适位置。不断递归,直到排好序为止。
时间复杂度:O(N*logN)

public class 简单排序4 {
public static void main(String[] args) {
	int []a= {9,0,12,3,6,22};
	QuickSort(a,0,a.length-1);//后两个参数表示要排序的数组的前后边界
	System.out.println("快速排序");
	for(int i=0;i<a.length;i++)
	{
		System.out.print(a[i]+" ");
	}
}
//快速排序
private static void QuickSort(int[] a,int p,int r) {
	// TODO Auto-generated method stub
	if(p<r)
	{
		int n=index(a,p,r);
		QuickSort(a, p, n-1);
		QuickSort(a, n+1, r);
	}
}
//单向扫描分区
private static int index(int[] a, int p, int r) {
	// TODO Auto-generated method stub
	int x=a[p];//定主元
	int left=p+1;//左指针
	int right=r;//右指针
	while(left<=right)
	{
		if(a[left]<=x)
		{
			left++;
		}
		else
		{
			int  term=a[right];
			a[right]=a[left];
			a[left]=term;
			right--;
		}
	}
	int term=a[right];
	a[right]=a[p];
	a[p]=term;
	return right;
}
}

在这里插入图片描述

5.归并排序:定主元位置直接就是数组中间下标,然后和快排一样,利用分治不断一分为二;再不断递归到有序,但是只是左侧和右侧各自有序,并不整体有序。这时需要归并两个数组为一个完整有序的数组。
时间复杂度:O(N*logN)

public class 简单排序5 {
public static void main(String[] args) {
	int []a= {8,4,0,12,13,6,9};
	MergeSort(a,0,a.length-1);
	System.out.println("归并排序");
	for(int i=0;i<a.length;i++)
	{
		System.out.print(a[i]+" ");
	}
}
//归并排序
private static void MergeSort(int[] a, int p, int r) {
	// TODO Auto-generated method stub
	if(p<r)
	{
		int mid=p+((r-p)>>1);
		MergeSort(a, p, mid);//左侧有序
		MergeSort(a, mid+1, r);//右侧有序
		Merge(a,p,mid,r);
	}
}
//归并
private static void Merge(int[] a,int p,int mid,int r) {
	// TODO Auto-generated method stub
	int help[]=new int[a.length];
	for(int i=0;i<a.length;i++)
	{
		help[i]=a[i];
	}
	int current=p;
	int left=p;
	int right=mid+1;
	while(left<=mid&&right<=r)
	{
		if(help[left]<=help[right])
		{
			a[current]=help[left];
			current++;
			left++;
		}
		else
		{
			a[current]=a[right];
			current++;
			right++;
		}
	}
	//如果右侧数组有剩余,他本身便在数组对应位置,所以不用管
	while(left<=mid)//如果左侧数组有剩余,全部放到数组末
	{
		a[current]=help[left];
		current++;
		left++;
	}
}
}

在这里插入图片描述
6.堆排序:
1.将待排序数组转化成完全二叉树或者近似完全二叉树
2.大顶堆化:父节点的值均大于子节点值
3.排序:每趟把本趟最大的数(大顶堆顶点)与本趟数组最后一个数交换,然后重新大顶堆化。所有节点都到顶点一次,就把所有数排好了顺序。
时间复杂度:O(N*logN)

public class 堆排序 {
public static void main(String[] args) {
	int []a= {12,7,11,3,6,8,9};
	HeapSort(a);//堆排序
	System.out.println("堆排序后");
	for(int i=0;i<a.length;i++)
	{
		System.out.print(a[i]+" ");
	}
}

private static void HeapSort(int[] a) {
	// TODO Auto-generated method stub
	//1.堆化成大顶堆
	MaxHeap(a);
	int n=a.length;//数组长度
	//2.排序
	for(int i=n-1;i>=0;i--)
	{
		int term=a[i];
		a[i]=a[0];
		a[0]=term;
		MaxHeapFixDown(a, 0, i);//向下堆化
	}
	
}
//大顶堆化
private static void MaxHeap(int[] a) {
	// TODO Auto-generated method stub
	int n=a.length;
	for(int i=n/2-1;i>=0;i--)//从倒数第二层的最后一个节点开始往上不断调整,因为最底的一层是叶子节点,不需要调整
	{
		MaxHeapFixDown(a,i,n);
	}
}
//大顶堆化向下调整
private static void MaxHeapFixDown(int[] a, int i, int n) {
	// TODO Auto-generated method stub
	int left=2*i+1;//左儿子
	int right=2*i+2;//右儿子
	if(left>=n)
	{
		return;//下标越界,意味着没有儿子
	}
	//走到这里了,意味着有左儿子
	int max=left;//暂时定此时两者中数值较大的是左儿子下标
	if(right>=n)
	{
		max=left;//此时不存在右儿子,所以两者中较大的那个数的下标是左儿子---------实锤
	}
	else {//此时左右儿子都存在
		if(a[right]>a[left])
		{
			max=right;//如果右儿子大,便取代max
		}
	}
	//至此,儿子中数值最大的儿子已经求出
	if(a[max]>a[i])//儿子中较大的那个与本来顶部比较,有比顶部大的才交换
	{
	int term=a[i];
	a[i]=a[max];
	a[max]=term;
	}
	MaxHeapFixDown(a, max, n);//递归地将此棵树下面的子树也调整一下,因为你调换之后,只能保证最近的三个节点满足大顶堆
	
}
}

在这里插入图片描述7.计数排序:开辟一个辅助数组,数组下标代表相对于min的相对大小,辅助数组中的内容代表这个值出现次数;扫描一遍原数组,其大小对应相对大小,每出现一次统计数值加一。最后扫描一遍辅助数组,恢复原来大小,输出即排好序。
时间复杂度:O(n)
计数排序适用于数值相对集中的区间,因为辅助空间的大小取决于最大值与最小值之差。如果范围大,需要开辟极大空间,但是很稀疏,浪费空间。对于范围相对集中的数来说,计数排序很快。
还有一种思路,戳这里

public class 完善以后的计数排序 {
public static void main(String[] args) {
	int []a= {5,2,2,1,33,12,-2};
	CountSort(a);
}
//计数排序
private static void CountSort(int[] a) {
	// TODO Auto-generated method stub
	//求最大值max
	int max=0;
	int min=0;
	for(int i=0;i<a.length;i++)
	{
		if(a[i]>max)
		{
			max=a[i];//最大值
		}
		if(a[i]<min)
		{
			min=a[i];//最小值
		}
	}
	int []help=new int[max-min+1];
	for(int i=0;i<a.length;i++)
	{
		int position=a[i]-min;//算出在辅助数组中的相对位置(相对于min)
		help[position]++;//统计出现次数
	}
	int current=0;//相当于回填原数组的指针
	for(int i=0;i<help.length;i++) 
	{
		for(int j=help[i];j>0;j--)
		{
			a[current]=min+i;//恢复原来值:方法是min+数组下标(数组下标是相对于min的大小)
			current++;
		}
	}
	System.out.println("计数排序");
	for(int i=0;i<a.length;i++)
	{
		System.out.print(a[i]+" ");
	}

}
}

在这里插入图片描述
8.桶排序:将数组中的值分成不同的区间(视为桶),然后对各个桶内数值进行排序,最后输出即可。计数排序可以看作是每个数值占一个桶的特殊桶排序。桶排序适用于数值稀疏的区间,如果数值太过于集中,数值会挤到一个桶里,桶排序失效。

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

public class 桶排序1 {
public static void main(String[] args) {
	int []a= {12,3,6,6,0,-7,10,-9};
	BucketSort(a);
}
//桶排序
private static void BucketSort(int[] a) {
	// TODO Auto-generated method stub
	//求最大值和最小值
	int max=0;
	int min=0;
	for(int i=0;i<a.length;i++)
	{
		if(a[i]>max)
		{
			max=a[i];
		}
		if(a[i]<min)
		{
			min=a[i];
		}
	}
	int sum=(max-min)/a.length+1;//需要的桶数
	ArrayList<ArrayList<Integer>> BucketArr=new ArrayList<>();//建立可变长的桶数组
	for(int i=0;i<sum;i++)//确定了桶的数量 
	{
		BucketArr.add(new ArrayList<Integer>());//挨个把桶放入可变长桶数组
	}
	for(int i=0;i<a.length;i++)
	{
		int num=(a[i]-min)/a.length;//算出每一个数值对应的桶号
		BucketArr.get(num).add(a[i]);//通过桶号找到对应的桶,然后将数值放进去	
	}
	for(int i=0;i<BucketArr.size();i++)
	{
		Collections.sort(BucketArr.get(i));
	}
	//最后输出排序后的结果
	System.out.println("桶排序后");
	System.out.println(BucketArr.toString());
}
}

在这里插入图片描述
9.基数排序:基数排序是一种特殊的桶排序,将待排序数组的数值,按个、十、百…位分别分类放入数值为0—9这10个桶中,每次按位数的值分一次后,都要将桶中排了一次的数值按顺序放回到原数组中,并且把桶清空以便只有使用。遍历最后的数组就是排了的顺序。
时间复杂度:O(n)

import java.util.ArrayList;

public class 基数排序1 {
public static void main(String[] args) {
	int []a= {15,3,0,6,12,15,-3,-1,-18,123};
	BaseSort(a);
}
//基数排序
private static void BaseSort(int[] a) {
	// TODO Auto-generated method stub
	//求最小值
	int min=0;
	for(int i=0;i<a.length;i++)
	{
		if(a[i]<min)
		{
			min=a[i];
		}
	}
	//使最小值至少为0
	int distance=0-min;
	if(distance>=0)//有负数再加
	{
	for(int i=0;i<a.length;i++)//每个值都加上差距,使最小值也为自然数,所有值都大于等于0
	{
		a[i]=a[i]+distance;
	}
	}
	//求最大值
	int max=0;
	for(int i=0;i<a.length;i++)
	{
		if(a[i]>max) 
		{
			max=a[i];
		}
	}
	int n=0;
	while(max>0)
	{
		max=max/10;
		n++;//算出最大值的位数,也就是需要进行的几轮
	}
//	System.out.println("最大值为"+max);
	ArrayList<ArrayList<Integer>> BucketArr=new ArrayList<ArrayList<Integer>>();//建立桶数组
	for(int i=0;i<10;i++)
	{
		BucketArr.add(new ArrayList<Integer>());//在可变长的桶数组中放上10个桶
	}
	for(int i=0;i<n;i++)//进行的轮数
	{
		for(int j=0;j<a.length;j++)
		{
			//提取本轮需要的位数值
			int term=a[j];
			for(int r=0;r<i;r++)
			{
				term=term/10;
			}
			int c=term%10;//本轮提取的位数值
			//根据位数值,将对应的值放到对应的桶中
			switch(c)
			{
				case 0:BucketArr.get(0).add(a[j]);break;
				case 1:BucketArr.get(1).add(a[j]);break;
				case 2:BucketArr.get(2).add(a[j]);break;
				case 3:BucketArr.get(3).add(a[j]);break;
				case 4:BucketArr.get(4).add(a[j]);break;
				case 5:BucketArr.get(5).add(a[j]);break;
				case 6:BucketArr.get(6).add(a[j]);break;
				case 7:BucketArr.get(7).add(a[j]);break;
				case 8:BucketArr.get(8).add(a[j]);break;
				case 9:BucketArr.get(9).add(a[j]);break;
			}
			
		}
		//将本轮桶中的数再放回数组中(入桶)
		int current=0;//原数组指针
		for(int v=0;v<BucketArr.size();v++)
		{
			for(int b=0;b<BucketArr.get(v).size();b++)
			{
				a[current]=BucketArr.get(v).get(b);
				current++;
			}
		}
		//每入桶出桶一次,清空所有的桶
		for(int y=0;y<BucketArr.size();y++)
		{
			BucketArr.get(y).clear();
		}
	}
	//恢复原来的值
	for(int i=0;i<a.length;i++)
	{
		a[i]=a[i]-distance;
	}
	//输出排序后的结果
	System.out.println("基数排序后");
	for(int i=0;i<a.length;i++)
	{
		System.out.print(a[i]+" ");
	}
	
}
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值