七大排序
排序方法 | 平均复杂度 | 最坏复杂度 | 最好复杂度 | 辅助空间 | 稳定性 | |
---|---|---|---|---|---|---|
选择排序 | O(n^2) | O(n^2) | O(n^2) | O(1) | 稳定 | |
冒泡排序 | O(n^2) | O(n^2) | O(n^2) | O(1) | 稳定 | |
插入排序 | O(n^2) | O(n^2) | O(n^2) | O(1) | 稳定 | |
归并排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 稳定 | |
快速排序 | O(nlogn) | O(n^2) | O(nlogn) | O(1) | 不稳定 | |
希尔排序 | O(nlogn)~O(n^2) | O(n^1.3) | O(n^2) | O(logn)~O(n) | 不稳定 | |
堆排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(1) | 不稳定 |
1.冒泡排序
简单解释
1.比较相邻的元素。如果第一个比第二个大,就交换他们两个。
2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
3.针对所有的元素重复以上的步骤,除了最后一个。
4.持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较
public static void bubbleSort(int arr[]) {
for(int i =0 ; i<arr.length-1 ; i++) {
for(int j=0 ; j<arr.length-1-i ; j++) {
if(arr[j]>arr[j+1]) {
int temp = arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
}
这里解释一下第二个for里面j<arr.length-1-i.为什么要-i呢,这个问题比较简单;
第一次i=0的时候,第二层循环依次比较j与j+1的大小,此次循环会把整个数组的最小值交换到最末尾的位置(假设排序是从大到小),当i=1时,此次循环会把整个数组第二个小的数交换到末尾位置(每次循环前面的数据都会有一定的改变,大数逐渐前移),以此类推。所以第二层循环比较到a.length是没有意义的,故
通过j<a.length-1-i来减少比较次数
要优化一下的话就给他加个标记flag,要你写冒泡排序也尽量写下面这种。
public static int[] bubbleSort(int arr[]) {
boolean flag;//是否交换的标志
for(int i =0 ; i<arr.length-1 ; i++) {
//设定一个标记,若为true,则表示此次循环没有进行交换,也就是待排序列已经有序,排序已经完成
flag = true;
for(int j=0 ; j<arr.length-1-i ; j++) {
if(arr[j]>arr[j+1]) {
int temp = arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
flag = false;//只有发生了交换,才为false
}
}
if (flag) {
break;//判断标志位是否为true,为true说明后面的元素已经有序,直接return出去
}
}
return arr;
}
2.选择排序
简单解释
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
重复第二步,直到所有元素均排序完毕。
public static void selectionSort(int[] arr){
for(int i = 0; i < arr.length - 1; i++){ // 交换次数
// 先假设每次循环时,最小数的索引为i
int min = i;// 每一个元素都和剩下的未排序的元素比较
for(int j = i + 1; j < arr.length; j++){
if(arr[j] < arr[min]){//寻找最小数
min = j;//将最小数的索引保存
}
}
//经过一轮循环,就可以找出第一个最小值的索引,然后把最小值放到i的位置
if (i != min) {
int tmp = arr[i];
arr[i] = arr[min];
arr[min] = tmp;
}
}
选择排序是一种简单直观的排序算法,无论什么数据进去都是 O(n²)的时间复杂度。
所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了
3.插入排序
插入排序是一种最简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
插入排序和冒泡排序一样,也有一种优化算法,叫做拆半插入。
简单解释
将第一待排序序列第一个元素看做一个有序序列,
把第二个元素到最后一个元素当成是未排序序列。
从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。
(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)
public static void insert_sort(int arr[]){
int temp;
// 从下标为1的元素开始选择合适的位置插入,因为下标为0的只有一个元素,默认是有序的
for(int i=0;i<arr.lenth-1;i++){
for(int j=i+1;j>0;j--){ //比较的次数是j和他前面的数据比较,比如第二个就只要和第一个比较,j=2就是比较1次了
if(array[j] < array[j-1]){ //和他前面的数据进行比较
temp = array[j-1];
array[j-1] = array[j];
array[j] = temp;
}else{ //不需要交换
break;
}
}
}
}
快速排序
public static void quickSort2(int[]arr,int left,int right){
//left指向最左边 0 ,right指向最右边 arr.length-1
//跳出循环的条件
if ((left >= right)){
return;
}
//l 和 r 作为指针
int l = left;
int r = right;
while (l < r) {
//选择left(每次的最左边的数)作为基准比较,直到r指针指向的数比基准小,此时r指向这个数,停止左移
//l指针同理,直到指向的数比基准大时,停止右移
while (l < r && arr[r] >= arr[left]) r--;
while (l < r && arr[l] <= arr[left]) l++;
//当l和r指针指向同一数,让l或r指针指向的数 跟基准数交换,此时基准数右边一定都是比他大的,左边都是比他小的
if (l == r){
int temp = arr[r];
arr[r] = arr[left];
arr[left] = temp;
}else {
//如果两指针没有指向同一数,让l指向的内容 和 r指向的内容交换
int temp = arr[r];
arr[r] = arr[l];
arr[l] = temp;
}
}
//递归:l指针左边的继续上述操作,r右边一样
quickSort2(arr, left,l-1);
quickSort2(arr, r+1, right);
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/111691.html