什么是排序
排序的定义
对一序列对象根据某个关键字进行排序(通俗点来说就是吧一堆数据按照从小到大(升序),或者从大到小排列(降序)),我们下面都基于升序来讲解。
排序的相关术语
- 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面
- 不稳定:如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面
- 内排序:所有排序操作都在内存中完成
- 外排序:由于数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行
- 时间复杂度: 一个算法执行所耗费的时间
- 空间复杂度:运行完一个程序所需内存的大小
排序的分类
算法分析
冒泡排序
冒泡排序(bulleSort)这里就不在多说了,非常经典的一种排序,我们接触的第一种排序啦。
算法描述:
- 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
- 从头到尾两两元素进行比较交换 ,这时尾部元素为最大元素
- 针对所有的元素重复以上的步骤,除了最后一个
- 重复步骤1~3,直到排序完成
算法分析
时间复杂度:
- 当数据有序时 最好 O(n)
- 当数据无序时 最差 O(n2)
空间复杂度O(1)
不稳定
实现代码
public static void bullSort(int[] array){
for(int i=0;i<array.length;i++)
{
int flag=0;
for(int j=0;j<array.length-1-i;j++)
{
if(array[j]>array[j+1])
{
int tmp=array[j];
array[j]=array[j+1];
array[j+1]=tmp;
flag=1;
}
}
if(flag==0)
{
break;
}
}
}
选择排序
选择排序(selectSort)是一种简单直观的排序算法。首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
算法描述
- 先将第一个元素开始,将第一个元素与后面的每一个元素进行比较,如果比其小,则进行交换,直到数组遍历完,第一个元素便是最小的元素
- 接着从第二个元素开始,与第二个元素之后的元素进行比较
- 重复上述过程
算法分析
时间复杂度:
- 当数据有序时 最好 O(n)
- 当数据无序时 最差 O(n2)
空间复杂度O(1)
稳定
实现代码
public static void selectSort(int[] array) {
for(int i=0;i<array.length-1;i++)
{
for(int j=i+1;j<array.length;j++)
{
if(array[j]<array[i])
{
int tmp=array[i];
array[i]=array[j];
array[j]=tmp;
}
}
}
}
希尔排序
希尔排序(shellSort)也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序,它与插入排序的不同之处在于,它会优先比较距离较远的元素(将小的数据尽可能的放到前面)希尔排序是把数据按照增量数组中得值分成好多个组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的数据越来越多,当增量减至1时,整个数据恰被分成一组,其实此时也就是插入排序了。(增量数组当中的值为素数,但最后一个是1)
算法描述
- 选择一个增量序列drr[]
- 从增量序列中取出第一个k,对序列进行分组,并对进行每组进行插入排序
- 选择增量序列中的下一个,重复2步骤
算法分析
算法分析
时间复杂度:
- 最好 O(n1.5)
- 最坏 O(n2)
空间复杂度O(1)
不稳定
实现代码
public static void shellSort(int[] array) {
int[] drr = {
5,3,1};//增量数组
for (int i = 0; i < drr.length; i++) {
shell(array,drr[i]);
}
}
public static void shell(int[] array ,int gap) {
int j,tmp;
for(int i=gap;i<array.length;i++)
{
tmp=array[i];
j=i-gap;
for(;j>=0;j-=gap)
{
if(array[j]>tmp)
{
array[j+gap]=array[j];
}else{
break;
}
}
array[j+gap]=tmp;
}
}
举例数组为[12,5,9,16,6,8,27,58,80,0,7,4,33,55,77]
增量序列为[5,3,1]
- 分五组
- 每组进行插入排序
- 在分三组,在进行插入排序
归并排序
归并排序(mergeSort)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。(原理-合并两个有序数组)
算法描述
来分析一下吧,对于归并算法,有两个部分组成,分解和合并。首先讲讲分解,我们需要将待排序的序列不停地进行分解,通过两个索引变量控制,一个初始索引(low),一个结尾索引(high)。只有当两索引重合才结束分解。接下来是合并,合并操作也是最麻烦的,也是通过两个索引变量s1,s2。开始s1在左边序列的第一个位置,s2在右边序列的第一个位置,然后就是寻找左右两个序列中的最小值(合并两个数组),放到新序列中,这时可能会出现一边的元素都放置完毕了,而另外一边还存在元素,此时只需将剩余的元素按顺序放进新序列即可,因为这时左右两边的序列已经是有序的了,最后将新序列复制到旧序列。这里也特别需要注意,因为合并的过程是分步的,而并非一次合并完成,所以数组的索引是在不断变化的。(所以需要加strat保证位置的正确性)
算法分析
时间复杂度:
- 最好:O(nlogn)
- 最坏:O(nlogn)
空间复杂度 O(n)
稳定
实现代码
- 递归实现
public static void mergeSort(int[] array)