基础算法-排序(插入&希尔&归并)
基本概念
排序算法有哪些
快速排序、冒泡排序、希尔排序、二分(归并)排序O(nlogn)、桶排序、堆排序、基数排序、插入排序O(n^2)、选择排序
插入&希尔&归并
冒泡&选择&快速
堆排序:树论高级篇
分析排序算法的几个方面:
1.时间复杂度
2.空间复杂度
3.比较次数&交换次数:排序肯定有比较和交换两个操作,
4.稳定性:(相同的两个元素,排序后相对位置不变)
1 9 3(1) 5 3(2)
1 3(1) 3(2) 5 9排序后是这样而不是1 3(2) 3(1) 5 9
稳定排序有什么意义?应用在哪里?
电商里面订单排序:首先按金额大小从小到大排序,金额相同的按下单时间。从订单中心过来时已经按照时间排好序,要求进行金额排序:
1 8:01 65
2 20:05 30
3 21:10 30
4 22:01 45
选择排序算法:如果选择不稳定的排序算法,就要比较两次,如果选择稳定的排序算法,那就只要比较一个字段。
插入排序(稳定的)
类似于打扑克
一个有序的数组,往里面添加一个新的数据后,如何继续保持数据的有序呢?找到数据应该插入的数据将其插入即可。(把一个无序的数列一个个插入到有序的数列中)
实现步骤:
1.将数组分成已经排序段和未排序段。初始化时排序段只有一个元素
2.到未排序段去元素插入到已排序段,并保证插入后仍然有序
3.重复执行以上操作,直到未排序段元素全部加完
代码实现
package Sort;
public class InsertSort {
/*
* 插入排序
* 1.将数组分成已经排序段和未排序段。初始化时排序段只有一个元素
* 2.到未排序段去元素插入到已排序段,并保证插入后仍然有序
* 3.重复执行以上操作,直到未排序段元素全部加完
*/
public static void main(String[] args) {
int a[]={9,8,7,0,1,3,2};
int n=a.length;
//这有两层循环
//时间复杂度O(n^2)
//最好时间复杂度O(n);
for (int i=1;i<n;i++){//为什么从i开始,第一个不用排序,我们从i分开,0~i的认为已经排好序
int data =a[i];
int j;
for(j=i-1;j>=0;j--){ //从尾到头在排好序的部分进行遍历,从后往前遍历 找到插入的数据时,需要往后移位置(数组元素移位)因此不用从头到尾
if(a[j]>data){
a[j+1]=a[j]; //往后移动
}else{ //前面是排好序的,找到一个比data小的不用再找
break;//break执行的越多,程序的效率就越高
}
}
a[j+1]=data;
System.out.print("第"+i+"次的排序结果为:");
for(j=0;j<n;j++){
System.out.print(a[j]+" ");
}
System.out.println();
}
}
}
运行结果:
第1次的排序结果为:8 9 7 0 1 3 2
第2次的排序结果为:7 8 9 0 1 3 2
第3次的排序结果为:0 7 8 9 1 3 2
第4次的排序结果为:0 1 7 8 9 3 2
第5次的排序结果为:0 1 3 7 8 9 2
第6次的排序结果为:0 1 2 3 7 8 9
希尔排序(对插入排序的优化)(不稳定的)
具体过程:
按照一个增量分段:add=n/2 n=10=>5=>2=>1
7 8 9 0 4 3 1 2 5 10
7和3一组,8和1一组·········
3 8 9 0 4 7 1 2 5 10以此类推完成第一次排序
结果:3 1 2 0 4 7 8 9 5 10
3 2 4 8 5一组(增量为2的分为一组)剩下1 0 7 9 10一组
最后去增量为1的一组
希尔排序的优化原理就是使得增量为1时数列中有序得到数更过,增加插入排序代码中第24行break的执行次数达到优化效果
归并排序(稳定的)
具体过程演示
有n个元素需要分logn次
9 5 6 8 0 3 7 1
9 5 6 8 · 0 3 7 1
9 5 · 6 8 · 0 3 · 7 1
以上为分的过程
以下为并的过程
5 9 · 6 8 · 0 3 · 1 7
5 6 8 9 · 0 1 3 7
0 1 3 5 6 7 8 9
分析:
时间复杂度:O(nlogn)
其他的和插入排序一样
代码实现
package Sort;
import java.util.Arrays;
public class MergeSort {
private static int temp[];
public static void main(String[] args) {
int data []={10,9,5,6,8,0,3,7,1};
temp = new int [data.length];
mergeSort(data, 0, data.length-1);
System.out.println(Arrays.toString (data));//Arrays.toString (data)直接打印数组
}
public static void mergeSort(int data[],int left,int right) { //left和right是数组的两端
if (left<right){ //相等之后就表示只有一个数了,不再拆了
int mid =(left+right)/2;
mergeSort(data, left, mid);
mergeSort(data, mid+1, right);
//分完了,接下来进行合并
merge(data, left, mid, right);
}
}
public static void merge(int data[],int left,int mid, int right){
//int temp[]=new int [data.length]; 不在此处开辟数组是为了防止数据量过大时,每次开辟内存时间过长
int point1 = left; //表示左边第一个数的位置
int point2 = mid+1; //表示右边第一个数的位置
int local = left; //表示当前已经到的哪个位置,因为最开始从左边开始
while (point1 <= mid && point2 <= right){
if (data[point1]<data[point2]){
temp[local]=data[point1];
point1++;
local++;
}else{
temp[local]=data [point2];
point2++;
local++;
}
}
while (point1 <=mid){
temp[local++]=data[point1++];
}
while (point2<=right){
temp[local++]=data[point2++];
}
for (int i=left;i<=right;i++){
data[i]=temp[i];
}
}
}