各种排序的时间、空间复杂度:
稳定性是指排序中相同的数在排序前后,他们的相对位置不会发生改变。
1.直接插入排序
经常碰到这样一类排序问题:把新的数据插入到已经排好的数据列中。
-
将第一个数和第二个数排序,然后构成一个有序序列
-
将第三个数插入进去,构成一个新的有序序列。
-
对第四个数、第五个数……直到最后一个数,重复第二步。
如何写成代码:
-
首先设定插入次数,即循环次数,for(int i=1;i<length;i++),1个数的那次不用插入。
-
设定插入数和得到已经排好序列的最后一个数的位数。insertNum和j=i-1。
-
从最后一个数开始向前循环,如果插入数小于当前数,就将当前数向后移动一位。
-
将当前数放置到空着的位置,即j+1。
代码实现如下:
public class Test {
public static void main(String[] args) {
int[] c = {1,3,5,7,9,8,6,4,2,0};
for(int i=1;i<c.length;i++){
int position = i;
int current = c[i];
for(int j=i-1;j>=0;j--){
//先让一段有序,再依次往后遍历,依次插入。
if(c[j] > current){
c[j+1]=c[j];
position--;
}
}
c[position] = current;
}
//打印排好序列
for(int q=0;q<c.length;q++){
System.out.print(c[q]+" ");
}
}
}
2.希尔排序
对于直接插入排序问题,数据量巨大时。
-
将数的个数设为n,取奇数k=n/2,将下标差值为k的书分为一组,构成有序序列。
-
再取k=k/2 ,将下标差值为k的书分为一组,构成有序序列。
-
重复第二步,直到k=1执行简单插入排序。
如何写成代码:
-
首先确定分的组数。
-
然后对组中元素进行插入排序。
-
然后将length/2,重复1,2步,直到length=0为止。
public class Test {
public static void main(String[] args) {
int[] c = {1,3,5,7,9,8,6,4,2,0};
ShellSort(c);
//打印排好序列
for(int q=0;q<c.length;q++){
System.out.print(c[q]+" ");
}
}
public static void ShellSort(int[] a){
int d = a.length;
while(d>0){
d=d/2;
for(int x=0;x<d;x++){
for(int i=x+d;i<a.length;i+=d){
int j=i-d;
int current = a[i];
// while(j>=0 ){
// if(a[j] > current){
// a[j+d] = a[j];
// }
// j-=d;
// }
//此处有两个判断条件,当都满足是才执行。不要写成上面的错误方式。
for(;j>=0&¤t < a[j];j-=d){
a[j+d]=a[j];
}
a[j+d] = current;
}
}
}
}
}
3.简单选择排序
常用于取序列中最大最小的几个数时。
(如果每次比较都交换,那么就是交换排序;如果每次比较完一个循环再交换,就是简单选择排序。)
-
遍历整个序列,将最小的数放在最前面。
-
遍历剩下的序列,将最小的数放在最前面。
-
重复第二步,直到只剩下一个数。
如何写成代码:
-
首先确定循环次数,并且记住当前数字和当前位置。
-
将当前位置后面所有的数与当前数字进行对比,小数赋值给key,并记住小数的位置。
-
比对完成后,将最小的值与第一个数的值交换。
-
重复2、3步。
代码实现如下:
public class Test {
public static void main(String[] args) {
int[] c = {1,3,5,7,9,8,6,4,2,0,10};
int i,j,k;
//选择排序
for(i=0;i<c.length-1;i++){
k=i;
for(j=i+1;j<c.length;j++){
if(c[k] > c[j]){
k=j;
}
}
{int temp = c[i];c[i]= c[k];c[k]=temp;}
}
for(int q=0;q<c.length;q++){
System.out.print(c[q]+" ");
}
}
}
4.冒泡排序
一般不用。
-
将序列中所有元素两两比较,将最大的放在最后面。
-
将剩余序列中所有元素两两比较,将最大的放在最后面。
-
重复第二步,直到只剩下一个数。
如何写成代码:
-
设置循环次数。
-
设置开始比较的位数,和结束的位数。
-
两两比较,将最小的放到前面去。
-
重复2、3步,直到循环次数完毕。
代码实现如下:
public class Test {
public static void main(String[] args) {
int[] c = {1,3,5,7,9,8,6,4,2,0,10};
int i,j;
//冒泡排序
for(i=0;i<c.length-1;i++){
for(j=0;j<c.length-i-1;j++){
if(c[j]>c[j+1]){
int temp = c[j];
c[j] = c[j+1];
c[j+1] = temp;
}
}
}
for(int q=0;q<c.length;q++){
System.out.print(c[q]+" ");
}
}
}
5.快速排序
要求时间最快时。
-
选择第一个数为p,小于p的数放在左边,大于p的数放在右边。
-
递归的将p左边和右边的数都按照第一步进行,直到不能递归。
public class Test {
public static void main(String[] args) {
int[] c = {1,3,5,7,9,8,6,4,2,0};
QuickSort(c, 0, c.length-1);
//打印排好序列
for(int q=0;q<c.length;q++){
System.out.print(c[q]+" ");
}
}
public static void QuickSort(int[] a,int start,int end){
if(start < end ){
int base = a[start];
int i= start,j=end;
do{
while(i < end && a[i] < base)i++;
while(j > start && a[j] > base)j--;
if(i<=j){
int temp = a[i];
a[i] = a[j];
a[j] = temp;
i++;j--;
}
}while(i<=j);
if(i< end)
QuickSort(a,i,end);
if(j > start)
QuickSort(a,start,j);
}
}
}
6.归并排序
速度仅次于快排,内存少的时候使用,可以进行并行计算的时候使用。
-
选择相邻两个数组成一个有序序列。
-
选择相邻的两个有序序列组成一个有序序列。
-
重复第二步,直到全部组成一个有序序列。
代码实现如下:
public class Test {
public static void main(String[] args) {
int[] c = {1,3,5,7,9,8,6,4,2,0};
//调用归并排序操作。
mergeSort2(c, 0, c.length-1);
//打印排好序列
for(int q=0;q<c.length;q++){
System.out.print(c[q]+" ");
}
}
public static void mergeSort2(int[] numbers,int start,int end){
if(start < end){
int mid = (start + end)/2;
mergeSort2(numbers,start,mid);
mergeSort2(numbers,mid+1,end);
merge2(numbers,start,end,mid);
}
}
private static void merge2(int[] numbers, int start, int end, int mid) {
int i = start,j=mid+1,k=0;
int[] temp = new int[end+1];
//两路归并操作。
while(i<=mid && j<=end){
if(numbers[i]<=numbers[j]){
temp[k++]=numbers[i++];
}else{
temp[k++]=numbers[j++];
}
}
//如果两个路的长度不一样,将长了的粘在缓存后面。
while(i<=mid){
temp[k++] = numbers[i++];
}
while(j<=end){
temp[k++] = numbers[j++];
}
//将排好的新数组赋值回原来的数组
for(i = 0;i<k;i++){
numbers[start+i]=temp[i];
}
}
}