数组二分查找与8种排序方法

二分查找

时间复杂度:O(log2n)
public class Hello{
    public static void main(String[] args){
        int[] arr = new int[]{1,2,3,5,7,12};
        int target = 12;		//查找的数
		int res;				//对应数的下标
        res = findIndex(arr,target);
        System.out.println(res);
    }
    public static int findIndex(int[] arr,int target){
		int left = 0;
        int right = arr.length-1;
        int mid;
        while(left <= right){
            mid = (left + right)/2;	//定位到区间中点
            if(arr[mid] == target){
                return mid;
            }else if(arr[mid] < target){
                left = mid + 1;		//排除中间点,定位右区间
            }else if(arr[mid] > target){
                right = mid - 1;	//排除中间点,定位左区间
            }
        }
        return -1;
    }
}

冒泡排序

原理:依次比较相邻的两个数,大泡往后面冒,小泡往前面冒
最差时间复杂度:O(n^2)
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 change = arr[j];
            arr[j] = arr[j+1];
            arr[j+1] = change;
        }
    }
}
可优化:新增flag变量,当数组本身已经排好序时,第一次循环内容未执行,此时flag=1,直接break
int flag = 1;
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 change = arr[j];
            arr[j] = arr[j+1];
            arr[j+1] = change;
            flag = 0;
        }
    }
    if(flag) break;
}

选择排序

原理:从0索引处开始,依次和后面每个元素做比较,小的元素往前放,经过一轮比较后,最小的元素就出现在了最小索引处。
时间复杂度:O(n^2)
for(int i = 0; i < arr.length-1; i++){
    for(int j = i; j < arr.length; j++){
        if(arr[i] > arr[j]){
            int t = arr[i];
            arr[i] = arr[j];
            arr[j] = t;
        }
    }
}

直接插入排序

原理:将一个个记录依次插入到一个长度为m的有序表中,使之仍保持有序。
(即将数组中较小的数往前搬)
for(int i = 1; i < arr.length; i++){
    for(int j = i; j > 0; j--){
        if(arr[j-1] > arr[j]){
            int t = arr[j];
            arr[j] = arr[j-1];
            arr[j-1] = t;
        }
    }
}

希尔排序

原理:又称缩小增量排序。先将原表按增量ht分组,每个子文件按照直接插入法排序。同样,用下一个增量ht/2将文件再分为子文件,再直接插入法排序。直到ht=1时整个文件排好序。
时间复杂度:O(n^(3/2))
int h = arr.length/2;    //增量设置为数组长度的一半
while(h>0){
    for(int i = h; i < arr.length; i++){
    	for(int j = i; j > h-1; j--){
     	   if(arr[j-h] > arr[j]){
            int t = arr[j];
            arr[j] = arr[j-h];
            arr[j-h] = t;
        }
    	}
    }
    h /= 2;
}
可采用克努特序列选取第一个增量,之后希尔排序时ht=(ht-1)/3
int ht = 1;
while(ht <= arr.length/3){
    ht = ht * 3 + 1;
}

快速排序

原理:分治法:比大小,再分区。从数组中取出一个数作为基准数,然后分区,将比这个数大或等于的数放右边,小于的这个数的放左边,再对左右区间重复此操作,直到各区间只有一个数。(例如体育课快速排队)
方法:挖坑填数法
时间复杂度:O(nlog2n)
public static void quickSort(int[] arr,int start,int end){
    if(start < end){	//对左右区间进行填坑操作,直到start==end
        int index = getIndex(arr,start,end);	//获取基准数填坑的位置
        quickSort(arr,start,index-1);	//左区间
        quickSort(arr,index+1,end);		//右区间
    }
}

public static int getIndex(int[] arr,int start,int end){   
    int i = start;
    int j = end;
    int x = arr[i];
    while(i < j){
        while(i < j && arr[j] >= x){	//从右往左找比基准数小的数
            j--;
        }
        if(i < j){
            arr[i] = arr[j];		//将找到的小的数填坑
            i++;
        }
        while(i < j && arr[i] < x){		//从左往右找比基准数大的数
            i++;
        }
        if(i < j){
            arr[j] = arr[i];		//将找到的大的数填坑
            j--;
        }
    }
    arr[i] = x;		//将基准数填坑
    return i;
}

归并排序

原理:先将长度为N的数组看成由N个有序的长度为1的数组组成,然后两两归并,得到N/2个长度为2或1的有序子序列,再两两归并,重复归并直到得到一个长度为N的有序序列为止。(2路归并排序)
时间复杂度:O(nlogn)
public static void Sort(int[] arr,int start,int end){
    int mid = (start + end)/2;
    if(start < end){	//对左右区间进行拆分,直到start==end
        Sort(arr,start,mid);	//拆分左区间
        Sort(arr,mid+1,end);	//拆分右区间
        guibin(arr,start,mid,end);		//归并排序
    }
}

public static void guibin(int[] arr,int start, int mid, int end){   
    int i = start;
    int j = mid + 1;
    int[] temp = new int[end-start+1];	//临时数组
    int k = 0;
    //将左右两个区间进行比较,依次将较小的数放入临时数组
    while(i <= mid && j <= end){
        if(arr[i] <= arr[j]){
            temp[k++] = arr[i];
            i++;
        }else{
            temp[k++] = arr[j];
            j++;
        }
    }
    //处理剩余元素
    while(i <= mid){
        temp[k++] = arr[i++];
    }
    while(j <= end){
        temp[k++] = arr[j++];
    }
    //将临时数组中的元素放到原数组中
    for(int h=0; h < temp.length; h++){
        arr[h+start] = temp[h];
    }
}
    

基数排序

原理:先找出数组中最大元素的位数为h,然后新建10个新数组,将原数组中的数字逐一判断个位数k,然后放进对应的第k个新数组中,直到数组为空时,将新数组中从第一个按顺序将元素放进原数组,接着将原数组中的数字逐一判断十位数k,重复上述操作,循环h次,则原数组排序完成。(牺牲空间换取时间)
时间复杂度:O (nlog®m)
public static void Sort(int[] arr){
    if(arr.length == 0) return;
    int max = getMax(arr);
    int len = String.valueOf(max).length();	//最大数的位数
    //定义二维数组,放10个桶
    int[][] temp = new int[10][arr.length];
    //定义统计数组,该数组索引与对应桶保持一致,索引对应值为桶的索引
    int[] count = new int[10];
    for(int i = 0,n = 1; i < len; i++,n*=10){
        for(int j = 0; j < arr.length; j++){
            int ys = arr[j] / n % 10;  //余数
            temp[ys][count[ys]++] = arr[j];
        }
        //取出桶中的元素
        int index = 0;
        for(int k = 0; k < count.length; k++){
            if(count[k] != 0){
                for(int h = 0; h < count[k]; h++){
                    arr[index++] = temp[k][h];
                }
                count[k] = 0;  //清楚上一次统计的个数
            }
        }
    }
}
public static int getMax(int[] arr){
    int max = arr[0];
    for(int i = 1; i < arr.length; i++){
        if(max < arr[i]){
            max = arr[i];
        }
    }
    return max;
}

堆排序

原理:将待排序序列构造成一个大顶堆,此时整个序列的最大值就是堆顶的根节点,将其与末尾元素进行交换,此时末尾就为最大值,然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值,如此反复执行,使能得到一个有序序列。
时间复杂度:O(nlogn)
public static void Sort(int[] arr){
		if(arr.length == 0) return;
		//定义开始调整的位置
		int start = (arr.length-1)/2;
		//调整成大顶堆
		for(int i = start; i >= 0; i--){
			bigSort(arr,arr.length,i);
		}
		//经过上面的操作后,已经将数组变成一个大顶堆,把根元素和最后一个元素进行调换
		for(int i = arr.length-1; i > 0; i--){
			//进行调换
			int t = arr[0];
			arr[0] = arr[i];
			arr[i] = t;
			//调换之后,将剩余元素调成大顶堆
			bigSort(arr,i,0);
		}
	}
	public static void bigSort(int[] arr, int size, int index){
		//获取左右子树的索引
		int left = index * 2 + 1;
		int right = index * 2 + 2;
		//查找最大节点对应的索引
		int maxIndex = index;
		if(left < size && arr[left] > arr[maxIndex]){
			maxIndex = left;
		}
		if(right < size && arr[right] > arr[maxIndex]){
			maxIndex = right;
		}
		if(maxIndex != index){
			int temp = arr[index];
			arr[index] = arr[maxIndex];
			arr[maxIndex] = temp;
			//调整完之后,可能会影响到下面的子树,不是大顶堆,还需调整
			bigSort(arr,size,maxIndex);
		}
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值