插入排序
/*插入排序*/
//第一步:将第一个数和第二个数排序,然后构成一个有序序列
//第二步:将第三个数插入进去,构成一个新的有序序列。
//第三步:对第四个数、第五个数……直到最后一个数,重复第二步。
public void insertSort(int[] a) {
int length=a.length;
int insertNum;
for(int i=1;i<length;i++)
{
insertNum=a[i]; //要插入的数
int j=i-1; //已经排序好的序列元素个数
//序列从后到前循环,将大于InsertNum的数向前移一位
while (j>=0&&a[j]>insertNum) {
a[j+1]=a[j];
j--;
}
a[j+1]=insertNum; //将要插入的数插在这个位置
}
}
冒泡排序
/*冒泡排序*/
//step1:将序列中所有元素两两比较,将最大的放在最后面。
//step2:将剩余序列中所有元素两两比较,将最大的放在最后面。
//step3:重复第二步,直到只剩下一个数。
public void bubbleSort(int[] a) {
int length=a.length;
int temp;
for(int i=0;i<length;i++)
{
for(int j=0;j<length-i-1;j++)
{
if(a[j]>a[j+1])
{
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
}
快速排序
/*快速排序*/
//选择第一个数为p,小于p的数放在左边,大于p的数放在右边。
//递归的将p左边和右边的数都按照第一步进行,直到不能递归。
public void quickSort(int[] numbers,int start,int end) {
if(start<end)
{
int base=numbers[start]; //选定的基准值(第一个数作为基准)
int temp;
int i=start,j=end;
do {
while((numbers[i]<base)&&(i<end))
i++;
while((numbers[j]>base)&&(j>start))
j--;
if(i<=j)
{
temp=numbers[i];
numbers[i]=numbers[j];
numbers[j]=temp;
i++;
j--;
}
} while (i<=j);
if(start<j)
quickSort(numbers, start, j);
if(end>i)
quickSort(numbers, i, end);
}
}
归并排序
/*归并排序*/
//将两个有序的数组归并成一个更大的有序数组。
//采用分治(divide and conquer)策略,
//利用递归每次将数组分成两半,
//直到子数组个数为1(1个元素的数组自然就有序的),
//将结果归并再返回。
public void mergeSort(int[] arr,int left,int right)
{
if(left<right) {
int mid=(left+right)/2;
//左边归并排序,使得左子序列有序
mergeSort(arr, left, mid);
//右边归并排序,使得右子序列有序
mergeSort(arr, mid+1, right);
//合并两个子序列
merge(arr, left, mid, right);
}
}
private void merge(int[] arr,int left,int mid,int right) {
int[] temp=new int[right-left+1];
int i=left;
int j=mid+1;
int k=0;
while(i<=mid&&j<=right)
{
if(arr[i]<arr[j]){
temp[k++]=arr[i++];
}
else {
temp[k++]=arr[j++];
}
}
//将左边剩余元素填充进temp中
while(i<=mid) {
temp[k++]=arr[i++];
}
//将右边剩余元素填充进temp中
while(j<=right) {
temp[k++]=arr[j++];
}
//将temp中的元素全部拷贝到原数组中
for(int k2=0;k2<temp.length;k2++)
{
arr[k2+left]=temp[k2];
}
}
简单选择排序
/*简单选择排序*/
//遍历整个序列,将最小的数放在最前面。
//遍历剩下的序列,将最小的数放在最前面。
//重复第二步,直到只剩下一个数。
public void selectSort(int[] a)
{
int length=a.length;
for(int i=0;i<length;i++)
{
int key=a[i];
int position=i;
for(int j=i+1;j<length;j++)
{
if(a[j]<key)
{
key=a[j];
position=j;
}
}
a[position]=a[i]; //交换位置
a[i]=key;
}
}
堆排序
参考文章
https://www.cnblogs.com/skywang12345/p/3602162.html
/*堆排序(从小到达)*/
//将序列构建成大顶堆。
//将根节点与最后一个节点交换,然后断开最后一个节点。
//重复第一、二步,直到所有节点断开。
public void heapSortAsc(int[] a)
{
int i,temp;
int length=a.length;
//从(length/2-1)--->0逐次遍历。遍历后后得到的是一个最大二叉堆
for(i=length/2-1;i>=0;i--)
{
maxHeapDown(a,i,length-1);
}
// 从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素
for(i=length-1;i>0;i--)
{
temp=a[0];
a[0]=a[i];
a[i]=temp;
// 调整a[0...i-1],使得a[0...i-1]仍然是一个最大堆。
// 即,保证a[i-1]是a[0...i-1]中的最大值。
maxHeapDown(a, 0, i-1);
}
}
/*
11 * (最大)堆的向下调整算法
12 *
13 * 注:数组实现的堆中,第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。
14 * 其中,N为数组下标索引值,如数组中第1个数对应的N为0。
15 *
16 * 参数说明:
17 * a -- 待排序的数组
18 * start -- 被下调节点的起始位置(一般为0,表示从第1个开始)
19 * end -- 截至范围(一般为数组中最后一个元素的索引)
20 */
private void maxHeapDown(int[] a,int start,int end)
{
int c=start;
int l=2*c+1;
int temp=a[c];
for(;l<=end;c=l,l=2*l+1)
{
// "l"是左孩子,"l+1"是右孩子
if(l<end&&a[l]<a[l+1])
l++; // 左右两孩子中选择较大者,即m_heap[l+1]
if(temp>=a[l])
break; // 调整结束
else { // 交换值
a[c]=a[l];
a[l]=temp;
}
}
}
希尔排序
参考文章
https://blog.csdn.net/qq_37592492/article/details/81157153
//希尔排序
//将数的个数设为n,取奇数k=n/2,将下标差值为k的书分为一组,构成有序序列。
//再取k=k/2 ,将下标差值为k的书分为一组,构成有序序列。
//重复第二步,直到k=1执行简单插入排序。
public void shellSort(int[] a)
{
int length=a.length;
//gap为步长,每次减少为原来一般
for(int gap=length/2;gap>0;gap=gap/2)
{
//共gap个组,每一组都执行直接插入排序
for(int i=0;i<gap;i++)
{
//插入排序
for(int j=i+gap;j<length;j+=gap)
{
//如果a[j]<a[j-gap],则寻找a[j]的位置
//并将后面的数据位置后移
if(a[j]<a[j-gap])
{
int temp=a[j];
int k=j-gap;
while(k>=0&&a[k]>temp)
{
a[k+gap]=a[k];
k=k-gap;
}
a[k+gap]=temp;
}
}
}
}
}
基数排序
参考文章
https://blog.csdn.net/qq_42857603/article/details/82351864
/*基数排序*/
//将所有的数的个位数取出,按照个位数进行排序,构成一个序列。
//将新构成的所有的数的十位数取出,按照十位数进行排序,构成一个序列。
//依次类推
public void radixSort(int[] a)
{
//求最大位数
int k=getNumberCount(getMax(a));
//count数组用来计数
int[] count=new int[10];
//bucket用来当桶
int[] bucket=new int[a.length];
//m表示第几位,1代表个位,2代表十位
for(int m=1;m<=k;m++)
{
//把count置空,防止上次循环数据的影响
for(int i=0;i<10;i++)
{
count[i]=0;
}
//分别统计第k位是0,1,2,3,4,5,6,7,8,9的数量
//即此循环用来统计每个桶中的数据的数量
for(int i=0;i<a.length;i++)
{
count[getFigure(a[i], m)]++;
}
//利用count[i]来确定放置数据的位置
for(int i=1;i<10;i++)
{
count[i]=count[i]+count[i-1];
}
//执行完此循环之后的count[i]就是第i个桶右边界的位置
//利用循环把数据装入各个桶中,注意是从后往前装
for(int i=a.length-1;i>=0;i--)
{
int j=getFigure(a[i], m);
bucket[count[j]-1]=a[i];
count[j]--;
}
//将桶中数据取出来,赋值给a
for(int i=0;i<a.length;i++)
{
a[i]=bucket[i];
}
}
}
private int getFigure(int a,int m)
{
int h=(int)Math.pow(10, m-1);
return (a/h)%10;
}
private int getNumberCount(int maxNum)
{
int num=1;
int t=maxNum/10;
while(t!=0)
{
num++;
t=t/10;
}
return num;
}
private int getMax(int[] a)
{
int max=a[0];
for(int i=1;i<a.length;i++)
{
if(a[i]>max)
{
max=a[i];
}
}
return max;
}
计数排序
/**
* 计数排序
*/
public class CountSort {
public static int[] countSort(int[] array){
//得到数列的最大值和最小值,并算出差值
int max=array[0];
int min=array[0];
for(int i=0;i<array.length;i++){
if(array[i]>max)
max=array[i];
if(array[i]<min)
min=array[i];
}
int d=max-min;
//创建统计数组并统计对应元素的个数
int[] countArray=new int[d+1];
for(int i=0;i<array.length;i++){
countArray[array[i]-min]++;
}
//3统计数组做变形,后面的元素等于前面的元素之和
for(int i=1;i<countArray.length;i++){
countArray[i]+=countArray[i-1];
}
//倒序遍历原始数组,从统计数组中找到正确位置,输出到结果数组
int[] sortedArray=new int[array.length];
for(int i=array.length-1;i>=0;i++){
sortedArray[countArray[array[i]-min]-1]=array[i];
countArray[array[i]-min]--;
}
return sortedArray;
}
}
桶排序
import java.util.*;
public class bucketSort {
public static double[] bucketSort(double[] array){
//得到数列的最大值和最小值,并算出差值d
double max=array[0];
double min=array[0];
for(int i=1;i<array.length;i++){
if(array[i]>max)
max=array[i];
if(array[i]<min)
min=array[i];
}
double d=max-min;
//初始化桶
int bucketNum=array.length;
ArrayList<LinkedList<Double>> bucketList=new ArrayList<LinkedList<Double>>(bucketNum);
for(int i=0;i<bucketNum;i++){
bucketList.add(new LinkedList<Double>());
}
//遍历原始数组,将每个元素放入桶中
for(int i=0;i<array.length;i++){
int num=(int)((array[i]-min)*(bucketNum-1)/d);
bucketList.get(num).add(array[i]);
}
//对每个桶类别进行排序
for(int i=0;i<bucketList.size();i++){
Collections.sort(bucketList.get(i));
}
//输出全部元素
double[] sortedArray=new double[array.length];
int index=0;
for(LinkedList<Double> list:bucketList){
for(double ele:list){
sortedArray[index]=ele;
index++;
}
}
return sortedArray;
}
public static void main(String[] args) {
double[] array=new double[]{4.12,3.14,3.56,4.32,5.89,9.02};
double[] sortedArray=bucketSort(array);
System.out.println(Arrays.toString(sortedArray));
}
}
总结
不稳定:
选择排序(selection sort)— O(n2)
快速排序(quicksort)— O(nlogn) 平均时间, O(n2) 最坏情况; 对于大的、乱序串列一般认为是最快的已知排序
堆排序 (heapsort)— O(nlogn)
希尔排序 (shell sort)— O(nlogn)
基数排序(radix sort)— O(n·k); 需要 O(n) 额外存储空间 (K为特征个数)
稳定:
插入排序(insertion sort)— O(n2)
冒泡排序(bubble sort) — O(n2)
归并排序 (merge sort)— O(n log n); 需要 O(n) 额外存储空间
二叉树排序(Binary tree sort) — O(nlogn); 需要 O(n) 额外存储空间
计数排序 (counting sort) — O(n+k); 需要 O(n+k) 额外存储空间,k为序列中Max-Min+1
桶排序 (bucket sort)— O(n); 需要 O(k) 额外存储空间