一、冒泡排序
int score[] = {67,100,50,99,87,89,90,75};
boolean flag = false;
/**
* 1、length方法用于获取数组的长度。
* 2、而length()用于获取String字符串中字符的个数。
* 第一轮计算的是需要几趟排序才能排完
*/
for (int i=0;i<score.length-1;i++){
//第二轮这个计算的是一趟排序内需要比较几次才能比较完
for (int j=0;j<score.length-1-i;j++){
if (score[j] > score[j+1]){
flag = true;
int number = score[j];
score[j] = score[j+1];
score[j+1] = number;
}
}
if (!flag){
//说明一次一次比较都没有发生,已经排好序了
break;
} else{
//说明至少排过一次序,重置标志才能有效
flag = false;
}
}
二、选择排序
int score[] = {67,100,50,99,87,89,90,75};
selectSort(score);
System.out.println(Arrays.toString(score));
}
private static void selectSort(int[] arr) {
//一共有几轮,比当前数组的长度少一轮
for (int i = 0; i < arr.length - 1; i++) {
/**
* 用于暂存数据,两个功能
* 一、比如:假设第一个是最小的,则记录第一个下标以及数据,实际第一个可能不是最小的
* 等到循环比较以后,第一个就变成最小的,则进行第二个数比较,取得最小值。
* 可以说是记录比较到了第几位
* 二、将暂存那个比假设的那个值要大的数,用于后续进行交换
*/
int midIndex = i;
int mid = arr[i];
//已经假设第一个是最小的,所以从第二个开始,与第一个进行比较
for (int j = i + 1; j < arr.length ; j++) {
//如果想按从大到小排序,可以把这里变成<
if (mid > arr[j]) {
//将比假设值要大的那个元素以及元素下标付给中间变量进行存储
midIndex = j;
mid = arr[j];
}
}
//等于的话,就相当于没有交换,本身就是最小的
if (midIndex != i) {
/**这下面两部不能反过来,否则会出错,因为原先大的元素已经放入mid这个中间值里面了
* 原先位置已经空出来了,所以要把arr[i]先放过去,然后再发mid中间值放入arr[i]中,
*/
//将原来假设小的放到后面,因为假设小的不是最小的,这里为什么用midIndex,就是因为那个被置换的小标是j是在里面的循环里面,只能先付给外面的才行
arr[midIndex] = arr[i];
//将比假设的值小的元素,付给原来假设小的元素的那个位置
arr[i] = mid;
}
}
}
三、插入排序
int[] scop = {3, 1, 5, 4, 9, 7, 6, 8};
insertSort(scop);
System.out.println("拍好后:"+ Arrays.toString(scop));
}
private static void insertSort(int[] arr) {
//循环几次,注意最后一位也要进行比较
for (int i = 1; i < arr.length; i++) {
//第一位是标志位,所以从第二位开始
int insertValue = arr[i];
//这里的意思就是,取前一位的下标,如果是从第二位开始,那就是第一位的下标也就是0
int insertIndex = i - 1;
/**
* 1、insertIndex >= 0:保证给insertValue这个数找插入的位置不越界
* 2、insertValue < arr[insertIndex]:如果标志位,也就是前一位比后一位,也就是要插入的哪一位要小,就不用插入了
*
*/
while (insertIndex >= 0 && insertValue < arr[insertIndex]) {
arr[insertIndex + 1] = arr[insertIndex];
insertIndex--;
}
/**
* 假如标志位是第一位,那么从第二位开始,
* insertValue 就是第二位,
* insertIndex 就是第一位的坐标
* arr[insertIndex + 1]其实就是第二位,相当于把第二位的值再付给他自己
*/
arr[insertIndex + 1] = insertValue;
System.out.println("每一轮排序:"+ Arrays.toString(arr));
}
}
四、快速排序
int[] scop = {3, 1, 5, 4, 9, 7, 6, 8};
quickSort(scop,0,scop.length-1);
System.out.println(Arrays.toString(scop));
}
private static void quickSort(int[] arr, int left, int right) {
int l = left;
int r = right;
int mid = arr[(left + right) / 2];
int temp =0;
//比mid小的放到左边,比mid大的放到右边
while (l < r) {
//从最左边找,比中间值小的,一直知道比中间值大的就退出
while (arr[l] < mid) {
l +=1;
}
//从最右边找,找到比mid小的,就退出
while(arr[r] > mid){
r -= 1;
}
//这里说明左边已经是全部小于等于中间值,右边已经全部是大于等于中间值
if (l>= r){
break;
}
//找到了,那就要开始交换了
temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
/**
* 其实就是mid这个值左右两边,刚好有两个和mid相等的数
* 然后这里只是在mid左边与mid相等时,去移动右边的下标,
* 然后右边的值和mid相等时,移动左边的下标而已
*/
//如果交换后,发现这个arr[l] == mid这个值,r--,前移
if (arr[l] == mid){
r -= 1;
}
//如果交换后,发现这个arr[r] == mid这个值,l++,后移
if (arr[r] == mid){
l += 1;
}
}
//如果l == r,必须l++,r--,否则会出现栈溢出
if(l ==r ){
l+=1;
r-=1;
}
//向左递归
if (left<r){
quickSort(arr, left, r);
}
//向右递归
if (right>l){
quickSort(arr, l, right);
}
}
五、分治算法
/**
* 归并排序
*/
public class test6 {
public static void main(String[] args) {
int[] scop = {3, 1, 5, 4, 9, 7, 6, 8};
int[] temp = new int[scop.length];
mergeSort(scop, 0, scop.length - 1, temp);
System.out.println(Arrays.toString(scop));
}
//分加合
public static void mergeSort(int[] arr, int left, int right, int[] temp) {
/**
* 这里用了递归
* (1)第一次:执行第一个 mergeSort 执行前判断:left=0,right=7
* 左边:3, 1, 5, 4 右边:9, 7, 6, 8 这是一次循环
* 进行第二次:执行第一个 mergeSort 数组是:3, 1, 5, 4 left=0,right=3
* 左边:3, 1 右边:5, 4
* 第三次:执行第一个 mergeSort 数组是:3, 1 left=0,right=1
* 左边:3 右边 1
* 第四次前:数组是:3 left=0,right=0
* 然后left < right不满足,跳出第四次循环的,
* 执行第三次循环中第二个mergeSort,右边数组为5, 4 执行前判断:mid 为 0 ,left=mid+1 = 1,right=1 不满足left < right
* 进入merge(),数组虽然是[3, 1, 5, 4, 9, 7, 6, 8],但是他只比较,3, 1,因为这是第三次循环中的元素----3,1 之后会比较5,4(注意如果第二个mergeSort里面还有递归,还会执行第一个
* mergeSort方法)
* 如此一致递归
*
*/
if (left < right) {
int mid = (left + right) / 2;
mergeSort(arr, left, mid, temp);
mergeSort(arr, mid + 1, right, temp);
merge(arr, left, mid, right, temp);
}
}
/**
* @param arr 排序的原始数组
* @param left 左边有序序列的初始索引。比如:分成两份后,这个就是左边那份的第一个索引
* @param mid 中间索引
* @param right 右边索引
* @param temp 做中转的数组
*/
public static void merge(int[] arr, int left, int mid, int right, int[] temp) {
int i = left; //初始化i为左边有序序列的初始索引
int j = mid + 1; //初始化j为右边有序序列的初始索引
int t = 0; //这向temp数组的当前索引
/**
* 一、
* 先把左右两边有序的数组按照规则填充到temp数组中,
* 直到有一边处理完为止
*/
while (i <= mid && j <= right) {
//如果左边的有序序列的当前元素,小于右边有序序列的当前元素,就将左边的当前元素转移到temp数组中,
// 然后左边数组下边加一,temp数组下边向后移一位
if (arr[i] <= arr[j]) {
temp[t] = arr[i];
t += 1;
i += 1;
} else {//反之将右边的放到temp当中
temp[t] = arr[j];
t += 1;
j += 1;
}
}
/**
* 二、
* 如果比完后还有剩下的,就将剩下的全部移动到temp数组当中
*/
while (i <= mid) {//左边还有剩
temp[t] = arr[i];
t += 1;
i += 1;
}
while (j <= right) {//右边还有剩
temp[t] = arr[j];
t += 1;
j += 1;
}
/**
* 三、
* 将temp数组元素拷贝到arr当中
* 注意不是每次都拷贝
*
* 就是合并的几个步骤
*/
t = 0;
int tempLeft = left;
//第一次合并 tempLeft = 0,right = 1 第二次:tempLeft = 2,right = 3 第三次:tempLeft = 0,right = 3
//最后一次合并:tempLeft = 0,right = 7
System.out.println("tempLeft=" + tempLeft + ",right = " + right);
while (tempLeft <= right) {
arr[tempLeft] = temp[t];
t += 1;
tempLeft += 1;
}
}
}
六、二分查找
/**
* 二分查找,只能用于有序的数组当中,
*/
public class test7 {
public static void main(String[] args) {
int[] scop = {1, 2, 3, 4, 5, 6, 7, 8};
System.out.println(binarySelect(scop,0,scop.length-1,5));
}
public static int binarySelect(int[] arr, int left, int right, int targ) {
//当左边大于右边时,退出递归,这是第一种情况
if (left > right) {
return -1;
}
int mid = (left + right) / 2;
//当目标值刚好和中间值相等时,就说明找到了,退出递归
int midValue = arr[mid];
if (targ > midValue) {
//这里会一直递归,知道找到和中间值相等,或者找不到的情况下,才会退出递归
return binarySelect(arr, mid + 1, right, targ);
} else if (targ < midValue){
return binarySelect(arr, 0, mid - 1, targ);
}else {
//返回找到的中间值
return mid;
}
}
}