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]+" ");
}
}
}