一、冒泡排序
-
原理:比较两个相邻的元素,如果说前一个元素的值比后一个元素的值大,则交换
-
思路: N个数字要排序完成,总共进行N-1趟排序,每i趟的排序次数为(N-i)次,所以可以用双重循环语句,外层控制循环多少趟,内层控制每一趟的循环次数
-
coding
public static void bubbleSort(int[] arr){
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]) {
swap(arr, j, j+1);
}
}
}
}
//这样做的前提,一定要保证不是同一块内存地址
public static void swap(int[] arr,int i, int j){
arr[i] = arr[i] ^ arr[j];
arr[j] = arr[i] ^ arr[j];
arr[i] = arr[i] ^ arr[j];
}
二、选择排序
- 原理:如果一个数组中有N个元素,首先从这N个数中挑出来一个最小的放到 [0] 的位置上,然后再从N-1个数中挑出一个最小的放到[1]位置上......依次类推
- coding
public static void selectSort(int[] arr){
if (arr.length == 0 || arr == null || arr.length == 1){
return;
}
int minIndex;
for (int i=0;i<arr.length;i++){
minIndex = i;
for (int j = i+1;j<arr.length-1;j++) {
minIndex = arr[minIndex]>arr[j]?j:minIndex;
}
swap(arr,i,minIndex);
}
}
public static void swap(int[] arr ,int i , int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
三、插入排序
-
原理:构建一个有序的序列,首先让他在 0 - 0上有序 然后就是在 0 - 1 上有序 0 - 2 有序 ...... 一直到0-N上有序。类似于我们抓牌,当抓到一张较小的拍的时候,我们通常是把它放在比它大的前一个位置。
-
coding
public static void insertSort(int[] arr){
// 0 - 0 上有序
// 0 - N 上有序
for (int i=1;i<arr.length;i++){
for (int j=i-1;j>=0;j--){
if (arr[j]>arr[j+1]){
swap(arr,j,j+1);
}
}
}
}
public static void swap(int[] arr,int i, int j){
arr[i] = arr[i] ^ arr[j];
arr[j] = arr[i] ^ arr[j];
arr[i] = arr[i] ^ arr[j];
}
四、归并排序
- 原理:核心的一个思想就是分而治之,将一整个较大规模的数据,进行一步一步的进行拆解,最后合并到一块
我是感觉这个图画的就已经很清楚了
首先看Merger的部分,如何进行Merge
- 过程:
- 准备一个临时的数组help
- 准备变量 i 用来记录 help数组的下标,p1 记录 arr数组的左边界, p2用来记录arr数组的右边界
- 在左边这部分的数组 和 在右边者部分的数组在不越界的情况下,如果谁的值小,谁就给help 同时 i++ p1++ 或者 p2++
- 当有一个不满足这个条件的时候退出循环,剩下的数依次放入到help 数组中
- 将help数组中的元素给arr
public static void merger(int[] arr , int L , int M , int R){
int[] help = new int[R-L+1];
int i=0;
int p1=L;
int p2=M+1;
while(p1<=M && p2<=R){
help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
}
while(p1<=M){
help[i++] = arr[p1++];
}
while(p2<=R){
help[i++] = arr[p2++];
}
for (i=0;i<help.length;i++){
arr[L+i] = help[i];
}
}
- 递归过程:
- 当L == R 递归终止条件
- 完成左边有序
- 完成右边有序
public static void process(int[] arr, int L , int R){
if (L == R){
return;
}
int mid = L + ((R-L)>>1);
process(arr,L,mid);
process(arr,mid+1,R);
merger(arr,L,mid,R);
}
五、快速排序
-
原理: 荷兰国旗的问题 + 随机值的选取
首先:要知道荷兰国旗问题,将一个数组分成左边小于某个number,中间的值是 number , 右边是大于number的值
- 解决思路:
- 将这个数组划分成两个边界分别是,小于边界和大于边界。
- 当 i 位置上的数小于 number 的时候 ,左边界的下一个值和当前元素交换 , i 跳下一个 , 小于区域进行右阔。
- 当 i 位置上的值等于 number 的时候 , i直接跳下一个。
- 当 i 位置上的元素大于 number 的时候 ,i位置上的元素和大于区域的前一个元素经行交换,然后 i 位置不动,大于区域向左边扩展。
- 荷兰国旗Coding
public static int[] partition(int[] arr , int L , int R){
int less = L - 1; //小于区域的右边界
int more = R; //大于区域的左边界
while(L<more){ //L 代表当前数的位置 arr[R] ---> 划分值
if (arr[L] < arr[R]){
swap(arr,++less,L++);
}else if (arr[L] > arr[R]){
swap(arr,--more,L);
}else {
L++;
}
}
swap(arr,more,R);
return new int[]{less+1,more}; //这里返回的是左边界和右边界的位置
}
- 划分值的选取 如果说划分值选的很偏,可能会退化成O(N^2), 举例:{1,2,3,4,5,6,7,8,9}
public static void quickSort(int[] arr,int L , int R){
if (L<R){
swap(arr,L + (int)(Math.random() * (R-L+1)),R);
int[] p = partition(arr,L,R);
quickSort(arr,L,p[0]-1); //小于区域做递归
quickSort(arr,p[1]+1,R); //大于区域做递归
}
}
六、堆排序
- 原理:heapInsert + heapIfy
- 堆排序Coding
public static void heapSort(int[] arr){
if (arr == null || arr.length<2)
return;
//首先变成大根堆
for (int i=0;i<arr.length;i++){
heapInsert(arr,i);
}
int heapSize = arr.length;
swap(arr,0,--heapSize); //让 索引 为0的位置和最后一个位置的元素进行交换
while(heapSize>0){
heapify(arr,0,heapSize);
swap(arr,0,--heapSize);
}
}
- heapInsert
- 调整成大根堆,然当前元素和它的父元素进行比较,如果当前元素大于它的父,那么让它进行向上窜
//变成大根堆,向上窜的过程
public static void heapInsert(int[] arr , int index){
//arr[index] > arr[(index-1)/2] 当前位置上的数和,父位置上的数进行比较,如果大与父位置上的数,则进行交换
while(arr[index] > arr[(index-1)/2]){
swap(arr,index,(index-1)/2);
index = (index-1)/2;
}
}
- heapIfy
- 同样是调整堆结构,这个heapIfy是将小的元素向下沉
public static void heapify(int[] arr,int index,int heapSize){
int left = index*2+1; //左孩子的下标
while(left<heapSize){ //左边的下标和heapSize作比较,小于heapSize证明没有越界
//比较两个孩子的值,谁的值大就将谁的下标给 largest
int largest = left+1<heapSize && arr[left+1]>arr[left]?left+1:left;
//父亲和孩子之间,谁的值大,把下标给largest
largest = arr[largest] > arr[index] ? largest:index;
//当前节点下面没有更大的节点了 break
if (largest == index){
break;
}
swap(arr,largest,index);
index = largest;
left = index*2+1;
}
}
总结: