冒泡排序,选择排序,归并排序,快速排序,二分法查找,反转链表-------------------java最基础算法

1----冒泡排序
    冒泡排序:核心就是两个for循环,外层控制从下标0开始的对比的循环次数,内层循环相邻两个元素对比找到最大值,如果i>i+1,则交换两元素,这样每一次找到的下标元素都是数组中的最大值,依次放到右边。

private void bubblingSort(int [] arr){
	int temp = 0;
	for(int i = 0; i < arr.length-1;i++){
		for(int j = 0; j < arr.length-1-i;i++){
			if(arr[j]>arr[j+1]){
				temp = arr[j];
				arr[j] = arr[j+1];
				arr[j+1] = temp; 
			}
		}
	}
}

二、选择排序
    选择排序的时间复杂度要比冒泡排序好,在力扣上刷题,冒泡排序是过不了审核的,时间复杂度太高,但是选择排序可以,当然算法排名也不怎么高,它的核心:

  1. 也是两个for循环,外层循环控制循环次数,每次循环将外层循环的i作为假定最小元素的下标,在未排序的位置找到最小元素,依次插入到当前队列i的位置
  2. 内层循环来找数组中有没有比假定最小元素还小的元素,
  3. 如果有,将假定最小元素下标替换为当前找到的最小元素,
  4. 这时候假定最小元素就会成为真正的最小元素,
  5. 此时内层循环也运行完毕,
  6. 在外层循环中,将当前数组下标为i的元素与假定最小元素交换位置,
  7. 这样每次内层循环走完,就会找到当前下标为i时的最小元素,插入到数组中的i位置,直到数组循环完毕
private void chooseSort(int [] arr){
	for(int i = 0; i<nums.length;i++){
		int least = i;
		for(int j = i+1;j<nums.length;j++){
			if(nums[j]<nums[least]){
				least = j;
			}	
		}
        if(i!=least){
            int temp = nums[least];
		    nums[least] = nums[i];
		    nums[i] = temp;    
        }
	}
}

三、归并排序
    归并排序:需要两个有序数组,create新数组,新数组长度是两个有序数组的length之和

  1. 定义三个int变量,两个有序数组的下标,一个新数组的下标
  2. 创建新数组,数组长度是两个有序数组的和
  3. 用while循环,控制条件就是两个有序数组的下标有没有超出各自数组长度,用&&作为连接符
  4. if对比两个有序数组的元素大小,谁小就把谁放到新数组,并且当前数组下标++,新数组下标也++;
  5. 如果有序数组的元素大小相同,则随意两个数组下标都++,当然新数组下标也++;
  6. 直到某一个数组下标超出了它的长度,跳出while循环
  7. 因为两个数组的长度不知道谁大谁小,所以在上面while循环之后,我们要补上那个数组长度更大的未查询到的数组元素,添加进新数组中,所以再写两个while循环
  8. 因为两个都是有序数组,所以剩下的元素一定比已经插入到新数组的元素要大,所以直接将剩余的数组元素赋值给新数组(相应的下标依然要++),这样归并排序就做完了
public static void mergeSort(int[] arr1,int[] arr2){
	int a = 0;
	int b = 0;
	int n = 0;
	int[] newArr = new int[arr1.length+arr2.length];
	while( a < arr1.length && b < arr2.length){
		if(arr1[a]<arr2[b]){
			newArr[n] = arr1[a];
			n++;
			a++;
		}else if(arr1[a] == arr2[b]){
			newArr[n] = arr1[a];
			n++;
			a++;
			b++;
		}else if(arr1[a]>arr2[b]){
			newArr[n] = arr2[b];
			n++;
			b++;
		}
	}
	while(a<arr1.length){
		newArr[n] == arr1[a];
		n++;
		a++;
	}
	while(b<arr2.length){
		newArr[n] == arr2[b];
		n++;
		b++;
	}
}

四、快速排序
快速排序核心思路:

  1. 先从数列中选择起始位置元素为基准数,以起始下标为i,尾标为j,从头和尾两个方向进行遍历,j–找到小于基准数的元素,将这个数据填到数列的下标i这里(因为起始下标i被记录成了基准数,所以不担心原数列下标i的元素会丢失),填完后 让i++自增一,因为这个时候arr[i]已经变成了刚刚查找到的小于基准数的元素,那么这个时候arr[i]肯定是小于基准数,无须再去遍历比较它,因此i++让下标移到i的下一位
  2. 在j也就是数量的尾部找到了一个比基准数小的元素,这个时候就出现了一个坑arr[j],这个元素被移走,就可以将i起始位置中大于基准数的元素移到arr[j]这个位置上,所以从i++开始找到一个元素大于基准数,填到arr[j]这里,同理j–,
  3. 重复1、2步骤,也就是用while循环(因为你不知道会循环多少次,因此用while)去做1、2的步骤,
  4. 一直到 i=j跳出循环,因为 i++和 j–导致总有一个坑没有被填数据,将基准数放到这个坑里,因为i=j,arr[i] = 基准数还是arr[j] = 基准数就没有区别了
  5. 这个时候你会发现,基准数左边的元素都是小于它的,右边都是大于它的,当然这个时候数列还是乱序,但是你能发现一种规律了,选出一个基准数每次总是让它左右元素小于它,右边大于它,不停的分割数列,让一小段数列再执行上述排序,直到起始下标或者等于尾部下标,终止程序,显然这就是递归的思想,
  6. 那么为什么基于递归分左右交换的算法时间性能会这么好,其实可以用一个公式来说明,k = m + n;k² > m² + n² (举例:5 = 2 +3 ,25 > 4 + 9)一小段一小段递归的时间复杂度要远小于其总和的时间复杂度,
  7. 快排的思想可以概括为:挖坑填数 + 递归分治法。力扣上能看到快排用时4ms,而选择排序用时1000ms起步,最高有1386ms,性能差距非常大,
class Solution {
    public int[] sortArray(int[] nums) {
        quickSort(nums,0,nums.length-1);
        return nums;
    }
    private void quickSort(int[] arr,int l,int r){
        int i = l;
        int j = r;
        if(l>=r){
            return ;
        }
        int temp = arr[i];
        while(j>i){
            while( j > i && arr[j] >= temp){
                j--;
            }//当此时跳出循环说明找到了arr[j]元素小于基准数temp
            if(j>i){
                //此时将arr[j]填入到arr[i]
                arr[i] = arr[j];
                i++;
    			//i方向元素向右移一位,i已经无需再比较
            }
            while( j > i &&arr[i]<temp){
                i++;
            }//当此时跳出循环说明找到了arr[i]元素大于基准数temp
            if(j>i){
                arr[j] = arr[i];//此时将arr[i]填入到arr[j]
                j--;//j方向元素向左移一位,j已经无需再比较
            }
        }
        arr[i] = temp;//当外层循环跳出来说明i = j,此时应当将基准数填入i或者j下标中
        //至此一次循环完成,应当以基准数下标i为界限,将数列分为两小段,递归调用再次去排序,直到l大于等于r,说明数列全部完成排序了
        quickSort(arr,l,i-1);
        quickSort(arr,i+1,r);
    }
}

五、二分法查找
    二分法查找:一个有序数组,一个元素key,查找key在数组中的下标位置,

  1. 定义一个起始下标,一个末尾下标,
  2. 先用if判断当前key是否在数组中,要是数组中根本没有这个元素,费老鼻子算力就乐子大了,因为是有序数组,只需要看key元素与数组的0下标和最后一位元素比大小,在这个范围中,就是正常的
  3. 用while循环,控制条件就是结束下标要大于=起始下标,
  4. 定义一个中间下标,取值就是中间下标=起始+末尾
  5. 在while循环里,if判断key与中间下标元素的大小,
  6. key大,则把起始下标移到中间下标的下一个
  7. 中间元素大,则把末尾下标移到中间下标的上一个
  8. 相等,说明这个下标就是key所对应的下标,直接return 下标
public static int binarySearch(int[] arr,int key){
	int start = 0;
	int end =arr.length-1;
	int center;
	//如果key不在数组中,直接return -1
	if( key < arr[start] || key > arr[end] || start > end){
		return -1;
	}
	while(start <= end){
		center = (start + end)/2
		if(key<arr[center]){
			//key在数组前半段
			end = center - 1;
		}else if(key == arr[center]){
			return center;
		}else if(key>arr[center]){
			//hey在数组后半段
			start = center + 1;
		}
	}
	return -1;
}

六、反转链表

//先定义节点的实体类
public Node{
    int data;
    Node next;
    public Node(int data,Node next;){
	   this.data = data;
	   this.next = next;
    }
}
//反转链表
public Node reverseList( Node node){
	Node prev = null;
	Node now = node;
	while(now != null){
		Node next = now.next;
		now.next = prev;
		prev = now;
		now = next;
	}
	return prev;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值