一,选择排序
1,思想
不断的找到数组中最小的元素,往数组前面放。(找第1小的元素放到位置1,找第2小的元素放到位置2,…,第n小的元素放到位置n)
2,图解
3,实现
/**
* 选择排序
* @param arr
*/
public static void sort(int[] arr){
if(null == arr || arr.length <= 1){
return;
}
for(int i = 1; i < arr.length; i++){
int min = arr[i - 1], minIndex = i - 1;
// 找到最小的元素
for(int j = i; j < arr.length; j++){
if(arr[j] < min){
min = arr[j];
minIndex = j;
}
}
swap(arr, minIndex,i - 1);
}
}
/**
* 交换元素
*/
public static void swap(int[] arr,int a,int b){
int tmp = arr[a];
arr[a] = arr[b];
arr[b] = tmp;
}
二,堆排序-大根堆
1,思想
不断的拿大根堆的根节点,结果就是一个降序排序
可以知道,我们通过二叉树的层序遍历给每个节点做个标记,标记为0~n,那么节点x(0<=x<=n)的父亲节点就是(x-1)/2向下取整的值。
节点上升:每个节点的值都小于它的父亲节点。所以只要不断的判断当前节点和父亲节点,就可以构建大根堆。(父亲和爷爷也要判断)
节点下降:把根节点取出来,把最后一个节点充当根节点,重新构造大根堆
2,图解
3,实现
/**
* 创建大根堆
* @param arr
*/
public static void createMaxHeap(int[] arr){
if(arr.length <= 1){
return;
}
int i = 0;
// 每个节点都要判断是否满足:小于父亲节点
while(i < arr.length){
int currentIndex = i;
int fatherIndex = (currentIndex-1)/2;
// 不断判断,自己->父亲->爷爷->太爷爷... 两两之间是否满足
while(fatherIndex < arr.length && fatherIndex >= 0 && arr[currentIndex] > arr[fatherIndex]){
swap(arr,currentIndex,fatherIndex);
currentIndex = fatherIndex;
fatherIndex = (fatherIndex-1)/2;
}
System.out.println(Arrays.toString(arr));
++i;
}
}
/**
* 获得根
* @param arr
*/
public static int[] getRoot(int[] arr){
// 获得根节点
System.out.println(arr[0]);
// 最后一个节点充当根节点
swap(arr,0,arr.length-1);
int[] ints = Arrays.copyOf(arr, arr.length - 1);
// 重构大根堆
createMaxHeap(ints);
return ints;
}
/**
* 交换元素
*/
private static void swap(int[] arr,int a,int b){
int tmp = arr[a];
arr[a] = arr[b];
arr[b] = tmp;
}
三,插入排序
1,思想
把一个数插入到已经排好序的数组中
2,图解
3,实现
/**
* 插入排序
* @param arr
*/
public static void sort(int[] arr){
for(int i = 1; i < arr.length; i++){
int j = i;
// 逐一和有序的元素比较和交换,最终找到自己的位置
while(j >= 1 && arr[j] < arr[j-1]){
swap(arr,j,j-1);
j -= 1;
}
}
}
/**
* 交换元素
*/
private static void swap(int[] arr,int a,int b){
int tmp = arr[a];
arr[a] = arr[b];
arr[b] = tmp;
}
四,希尔排序
1,思想
在插入排序的基础上,把原来的步子迈大一点
2,图解
3,实现
/**
* 希尔排序
* @param arr
*/
public static void sort(int[] arr){
if(null == arr || arr.length <= 1){
return;
}
int step = arr.length/2;
while(step != 0){
realSort(arr,step);
step /= 2;
}
}
/**
* 插入排序
* @param arr
* @param step
*/
private static void realSort(int[] arr,int step){
for(int i = step; i < arr.length; i += step){
int j = i;
while(j >= step && arr[j] < arr[j - step]){
swap(arr,j,j - step);
j -= step;
}
}
}
/**
* 交换元素
*/
private static void swap(int[] arr,int a,int b){
int tmp = arr[a];
arr[a] = arr[b];
arr[b] = tmp;
}
五,冒泡排序
1,思想
两两相邻元素大的往后走
2,图解
3,实现
/**
* 冒泡排序
* @param arr
*/
public static void sort(int[] arr){
for(int i=1; i<arr.length; i++){
for(int j=1; j<arr.length-i; j++){
// 大的往后走
if(arr[j-1]>arr[j]){
swap(arr,j,j-1);
}
}
}
}
/**
* 交换元素
*/
private static void swap(int[] arr,int a,int b){
int tmp = arr[a];
arr[a] = arr[b];
arr[b] = tmp;
}
六,快速排序
1,思想
我们知道,排好序的数组,对于其中的某个元素,该元素左边的元素一定小于等于该元素,右边一定大于等于该元素,快速排序就是根据这个特点找到每个元素的位置。
步骤:
1)选择一个基准,放到最后,左边一个标记,右边一个标记,
2)将左边标记向右移动,当遇到大于基准值的元素 或 超过右边标记 时,停下;
3)将右标记向左移动,当遇到小于基准值的元素时 或 超过左边标记 时,停下;
4)如果左边标记没有超过右边标记,则交换左右标记的值,执行步骤2;
5)如果左边标记超过右边标记,则将基准值和左边标记交换(不能和右边标记交换,因为我们一开始选择的基准值是放到最后,最后这个位置是属于右边的,必须大于等于基准值,同理,如果基准值在左边,则只能和右边标记交换),结束,此时找到了基准在数组中的正确位置。
2,图解
3,实现
/**
* 快速排序
* @param arr
* @param start 0
* @param end arr.length-1
*/
public static void sort(int[] arr,int start,int end){
if(start >= end){
return;
}
int i=start,j=end-1,key=arr[end];
while(true){
while(i<=j && key >= arr[i]){
i++;
}
while(i<=j && key <= arr[j]){
j--;
}
if(i<j){
swap(arr,i,j);
}else{
swap(arr,i,end);
break;
}
}
sort(arr,start,i-1);
sort(arr,i+1,end);
}
/**
* 交换元素
*/
private static void swap(int[] arr,int a,int b){
int tmp = arr[a];
arr[a] = arr[b];
arr[b] = tmp;
}
七,归并排序
1,思想
将有序的两个数组合并在一起
过程:
无序数组 =》 {3,2,4,1}
拆
折中拆 =》{3,2},{4,1}
折中拆 =》{3},{2},{4},{1}
拆到元素只有一个就停下
合,合并后保证有序,比如{3},{2}合并后不是{3,2},而是{2,3}
两两合并=》{2,3},{1,4}
两两合并=》{1,2,3,4}
2,图解
3,实现
/**
* 归并排序
* @param arr
* @param left
* @param right
*/
public static void sort(int[] arr, int left, int right){
if(left < right){
// 折中拆
int mid = (left + right) / 2;
sort(arr, left, mid);
sort(arr, mid + 1, right);
// 注意只能是mid + 1,换成mid的话,最后只能拆分到两个元素,而我们要的是拆分到一个元素
merge(arr, left, mid + 1, right); // mid + 1
}
}
/**
* 合并
* @param arr
* @param left
* @param mid
* @param right
*/
private static void merge(int[] arr,int left,int mid,int right){
int[] tmpArr = new int[right - left + 1];
int tmpLength = 0, leftEnd = mid - 1, left1 = left;
while(left <= leftEnd && mid <= right){
if(arr[left] <= arr[mid]){
tmpArr[tmpLength++] = arr[left++];
}else{
tmpArr[tmpLength++] = arr[mid++];
}
}
while(left <= leftEnd){
tmpArr[tmpLength++] = arr[left++];
}
while(mid <= right){
tmpArr[tmpLength++] = arr[mid++];
}
for(int i = 0; i < tmpLength; i++){
arr[left1++] = tmpArr[i];
}
}
/**
* 交换元素
*/
private static void swap(int[] arr,int a,int b){
int tmp = arr[a];
arr[a] = arr[b];
arr[b] = tmp;
}