- 选择排序:
每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。:
在元素集合array[i]–array[n-1]中选择关键码最大(小)的数据元素
若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换
在剩余的array[i]–array[n-2](array[i+1]–array[n-1])集合中,重复上述步骤,直到集合剩余1个元素直接选择排序的
时间复杂度:O(N^2)
空间复杂度:O(1)
稳定性:不稳定
代码实现:
public static void selectSort(int[] array){
for(int i=0;i<array.length;i++ ){
int j=0;
for(j=i+1;j<array.length;j++){
if(array[j]<array[i]){
int temp=array[i];
array[i]=array[j];
array[j]=temp;
}
}
}
}
2.堆排序
堆排序是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序要建小堆。
小根堆:任意一个节点的关键字值都小于等于它孩子节点的关键字值,即根节点值最小
大根堆:任意一个节点的关键字值都大于等于它孩子节点的关键字值,即根节点值最大
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190511205835453.png?x-oss-p
图解:
调整完进行的步骤是交换,将根节点值和最后一个值交换
所以:int temp=array[array.length-1] ,(因为最后一个元素为:array.length-1)
进行两个元素的交换: array[array.length-1-j]=array[0];
Array[0]=temp;
调整的时候不需要再调整有序的数据了,所以执行:adjust=(array,0,array.length-1-j-1);
总结:堆排序分两个阶段。首先将一个数据序列建成堆序列,根节点值是最大(小)值,然后采用选择排序的思路,每趟将根节点值交。换到后面,再将其余值调整成堆,依次重复,直到排序完成
代码实现:
//把这颗树调整为大根堆的时间复杂度是: log2(n)
public static void adjust(int[] array, int start, int end) {
int temp = array[start];
for (int i = 2 * start + 1; i <= end; i = 2 * i + 1) {
//找到左右 孩子最大值的下标
if ((i < end) && array[i] < array[i + 1]) { //肯定有右孩子
i++; //左右孩子的最大值下标
}
if (array[i] > temp) {
array[start] = array[i];
start = i;
}
else if (array[i] < temp) {
break;
}
}
array[start] = temp;
}
(2)交换
public static void heapSort(int[] array){
long start=System.currentTimeMillis();
for(int i=(array.length-1-1)/2;i>=0;i--){ //从最后一颗子树开始调整 //n/2
adjust(array,i,array.length-1); //log2(n)
}
//交换
for(int j=0;j<array.length-1;j++){
int temp=array[array.length-1-j];
array[array.length-1-j]=array[0];
array[0]=temp;
adjust(array,0,array.length-1-j-1); //调整的时候,不需要调整有序的数据
}
long end = System.currentTimeMillis();
System.out.println(end-start);
}
堆排序:将一个序列调整为堆的时间复杂度为O(logn),所以它的时间复杂度为O(nlogn)
空间复杂度为O(1)
3. 归并排序:
将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
图解:
代码实现:
public static void merge(int[] array,int start,int mid,int end) { //合并(某一个区间的合并)
int[] tmpArray = new int[array.length]; //重新申请一个数组
int tmpIndex = start; //放到当前归并段开始的位置
int s2 = mid + 1;
int i=start; //start一直在后移,定义i保存起来
while (start <= mid && s2 <= end) { //两个归并段都有数据时
if (array[start] >=array[s2]) {
tmpArray[tmpIndex]=array[s2];
s2++;
tmpIndex++;
}
else{
tmpArray[tmpIndex]=array[start];
start++;
tmpIndex++;
}
}
while(start<=mid){ //第二个归段没有数据,直接将第一个里剩下的拿下来
tmpArray[tmpIndex++]=array[start++];
}
while(s2<=end){
tmpArray[tmpIndex++]=array[s2++];
}
while(i<=end){
array[i]=tmpArray[i];
i++;
}
}
public static void mergeSort(int[] array,int start,int end){
if(start>=end){ //相等则结束
return;
}
int mid=(start+end)/2;
mergeSort(array,start,mid); //递归
mergeSort(array,mid+1,end); //分解
//肯定是一个一个有序
//合起来
merge(array,start,mid,end);
}
归并排序的空间复杂度为:O(n)
时间复杂度为:O(nlogn),稳定。
不需要进行比较比较的排序:
- 计数排序:
计数排序的思想类似于哈希表中的直接定址法,在给定的一组序列中,先找出该序列中的最大值和最小值,从而确定需要开辟多大的辅助空间,每一个数在对应的辅助空间中都有唯一的下标。
找出序列中最大值和最小值,开辟Max-Min+1的辅助空间
最小的数对应下标为0的位置,遇到一个数就给对应下标处的值+1,。
遍历一遍辅助空间,就可以得到有序的一组序列
步骤:
(1) 统计相同元素出现次数
(2) 根据统计的结果将序列回收到原来的序列中
(3) 图解;
稳定
代码实现:
private static int[] countSort(int[] array,int k)
{
int[] C=new int[k+1];//构造C数组
int length=array.length,sum=0;//获取A数组大小用于构造B数组
int[] B=new int[length];//构造B数组
for(int i=0;i<length;i++)
{
C[array[i]]+=1;// 统计A中各元素个数,存入C数组
}
for(int i=0;i<k+1;i++)//修改C数组
{
sum+=C[i];
C[i]=sum;
}
for(int i=length-1;i>=0;i--)//遍历A数组,构造B数组
{
B[C[array[i]]-1]=array[i];//将A中该元素放到排序后数组B中指定的位置
C[array[i]]--;//将C中该元素-1,方便存放下一个同样大小的元素
}
return B;//将排序好的数组返回,完成排序
}
2.基数排序:
构造一个二维数组:10*n,一个长度为n的数组用于存储每次位排序时每个桶里有多少个元素。
循环操作:从低位开始,将所有元素对应该位的数字存到相应的桶里去(对应二维数组的那一列),然后将所有桶里的元素按照桶标号从小到大取出,后放进去的后取出。继续下一位操作。
过程:
现有:73 22 93 43 55 14 28 65 39 81
(1) 按个位排序:
排序后的结果:
81 22 73 93 43 14 55 65 28 39
(2) 按十位排序:
排序后的结果:
14 22 28 39 43 55 65 73 81 93
代码实现:
private static void radixSort(int[] array,int d)
{
int n=1;//代表位数对应的数...
int k=0;//保存每一位排序后的结果用于下一位的排序输入
int length=array.length;
int[][] bucket=new int[10][length];//排序桶用于保存每次排序后的结果,这一位上排序结果相同的数字放在同一个桶里
int[] order=new int[length];//用于保存每个桶里有多少个数字
while(n<d)
{
for(int num:array) //将数组array里的每个数字放在相应的桶里
{
int digit=(num/n)%10;
bucket[digit][order[digit]]=num;
order[digit]++;
}
for(int i=0;i<length;i++)//将前一个循环生成的桶里的数据覆盖到原数组中用于保存这一位的排序结果
{
if(order[i]!=0)//这个桶里有数据,从上到下遍历这个桶并将数据保存到原数组中
{
for(int j=0;j<order[i];j++)
{
array[k]=bucket[i][j];
k++;
}
}
order[i]=0;//将桶里计数器置0,用于下一次位排序
}
n*=10;
k=0;//将k置0,用于下一轮保存位排序结果
}
}