注:鸡尾酒排序是双向冒泡排序,将在后面的blog中进行更新。
前言
各位小伙伴们,本次博客主要来与大家共同学习四大排序算法是如何实现的?你想不想了解一下冒泡是如何大数沉底的呢?选择是如何小数上浮的呢?插入算法是如何在有序数组中见缝插针的呢?如何实现高效率二分查找呢?快快快,接着往下读…
一、冒泡排序
日常想法:哈哈哈,看到这个图你有没有放弃人生的感觉,别急坚持一下,你就能弄懂冒泡泡的原理了。
1、算法实现
核心思想:通过一趟遍历将最大的数,冒到最后。我们将交换函数进行封装后再多次使用,只需要调用它就可以了。代码中将用j控制趟数,i控制每一次遍历的下标,这里因为可以确定遍历一趟肯定可以将该趟中的最大值固定在最后,遍历n趟可以固定n个数,这n个数不用在进行比较,所以i的约束条件是i<arr.length-1-i。
(要-1是为了防止下标越界)
public static void swap(int[] arr,int index1,int index2){
int temp=arr[index1];
arr[index1]=arr[index2];
arr[index2]=temp;
}
public static void bubbleSort(int[] arr){
boolean flag=false;
for(int j=0;j<arr.length;j++) {//j控制趟数
flag=false;//每一趟都是一个新的flag
for (int i= 0; i< arr.length-1-j; i++) { //要-1,防止i+1下标越界(每一趟操作思路)
if (arr[i] > arr[i + 1]) {
flag=true;
swap(arr, i, i + 1);
}
}
if(flag){
continue;
}else{
return; //break;跳出当前大循环(第一层循环)
}
}
}
代码中我们进行了优化,设置了标记遍历,是为了避免数组已经有序了,还在重复比较遍历的情况。
2、测试代码
public static void main(String[] args) {
int[] arr={2,3,1,6,4,7};
bubbleSort(arr);
System.out.println(Arrays.toString(arr));
}
3、结果展示
二、二分查找
1、算法实现
需要注意的问题:
(1)可能越界(L+R)/2 ——>(R-L)/2+L/2
(2)因为计算机中采用位运算,所以我们将/2操作改写为右移>>>,这样可以加快程序的运行速度。但需要注意运算符的优先级,给它加上小括号哦。
//TODO:二分查找(注意要为有序数组)
// 时间复杂度O(log2^n),空间复杂度O(1)没有开辟新的空间,与问题规模无关
public static int binarySearch(int arr[],int value){
int left=0;
int right=arr.length-1;
while(left<=right){
int mid=((right-left)>>>1)+left; //优化:1)越界问题 2)位运算优化,注意优先级
if(arr[mid]==value){
return mid;
}else if(arr[mid]<value){
left=mid+1;
}else{
right=mid-1;
}
}
return -1;//没有找到的情况
}
2、测试代码
public static void main(String[] args) {
int[]arr={3,4,6,8,9};
int a=binarySearch(arr,9);
System.out.println("该值所对应的下标为:"+a+" 值的大小是:"+arr[a]);
}
3、结果展示
三、选择排序
1、算法实现
可以将它与冒泡排序进行对比,冒泡排序是将大数想下沉,而选择排序是将小数向上浮。
//TODO:选择排序——>与冒泡相反,将小数往上冒(i控制有序序列,j在当前i以后的序列中找最小值)
public static void swap(int[]arr,int index1,int index2){
int temp=arr[index1];
arr[index1]=arr[index2];
arr[index2]=temp;
}
public static void selectSort(int[]arr){
if(arr==null||arr.length==0){
return;
}
int mindex;
for (int i=0;i<arr.length;i++){
//找最小值(假设起始位置为最小值)
mindex=i;
for(int j=i;j<arr.length;j++){
if(arr[mindex]>arr[j]){
mindex=j;
}
}
swap(arr,i,mindex);//最小元素和待排序相对的首位进行交换
}
}
2、测试代码
public static void main(String[] args) {
int[]arr={4,3,1,8,9};
selectSort(arr);
System.out.println(Arrays.toString(arr));
}
3、结果展示
对于这个算法的实现,我们也可以进行以下的优化:
优化思想:设置begin=0,end=arr.length-1,maxindex,mindex先开始存入arr[end]和arr[begin]的value,通过使用z进行数组遍历,当arr[z]>arr[maxind],将此时z赋给end,当arr[z]<arr[minindex]。当第一个位置和最后位置放上整个数组的最大值和最小值后,begin++,end–,然后再在无序数列中寻找最大值和最小值。(注意条件begin<end)
public static void selectSort(int[]arr){
if(arr==null||arr.length==0){
return;
}
int begin=0;
int end=arr.length-1;
int maxindex=arr[begin];
int minindex=arr[begin];
while(begin<end){
for(int z=begin;z<end;z++){
if(arr[z]>arr[maxindex]){
maxindex=z;
}
if(arr[z]<arr[minindex]){
minindex=z;
}
}
swap(arr,minindex,begin);
swap(arr,maxindex,end);
begin++;
end--;
}
}
总结:
这种优化方法并没有降低选择排序的时间复杂度,只是减少了数组的遍历次数。
四、插入排序
1、算法实现
核心将整个数组看成两个部分组成,一边是有序的数组,一边是无序数组,通过遍历无序数组,将无序数组的值插入到有序数组的合适位置。
public static void insertSort(int[]arr){
if (arr==null||arr.length==0){
return;
}
int j=0;
for(int i=0;i<arr.length-1;i++){
int temp=arr[i+1];
for(j=i;j>=0;j--){
if(arr[j]>temp){
arr[j+1]=arr[j];
}else{
arr[j+1]=temp;
break;
}
}
arr[j+1]=temp;
}
}
2、测试代码
public static void main(String[] args) {
int[]arr={4,3,1,8,9};
insertSort(arr);
System.out.println(Arrays.toString(arr));
}
3、结果展示
总结
哈哈哈,恭喜你!历经千辛万苦看的这里了,相信你已经对这四种算法了如指掌了叭,期待我们的下次相见哈!
算法 | 时间复杂度 |
---|---|
冒泡排序 | O(n^2) |
二分查找 | O(log2^n) |
选择排序 | O(n^2) |
插入排序 | O(n^2) |