以下代码均整理自互联网。
快排:// 见笔记本 10页快排的思路
public class Code_04_QuickSort {
public static void quickSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
quickSort(arr, 0, arr.length - 1);
}
public static void quickSort(int[] arr, int l, int r) {
if (l < r) {
//随机选一个位置的数与最后位置交换,形成随机快排。
// l + (int) (Math.random() * (r - l + 1)) 表示在l和r之间随机选一个数
swap(arr, l + (int) (Math.random() * (r - l + 1)), r);
//不要上一行就是经典快排
int[] p = partition(arr, l, r); //partiton划分的意思,这个是荷兰国旗问题
quickSort(arr, l, p[0]);
quickSort(arr, p[1], r);
//进来一组数据,分成左边一坨小于它,右边一坨大于它,然后对左边一坨,中间等于的一坨
//左边分出的一坨又重新这样做(因为同样的问题,所以调用自己),右边分出来的一坨也这样做,
// 所以递归多了后面那两个quikSort
//后面再本程序开头加上递归终止条件即可。归并排序也是这样的,只不过后面多了归并的部分。
}
}
public static int[] partition(int[] arr, int l, int r) {
int less = l - 1;
int more = r;//因为是用最后一个数作为基准数的,所以这里是r,后面记得把这个基准数
// 放到中间相等的部分,且more是中间相等部分的上一个数,自己可以找两个数想一想。
while (l < more) { //因为l有时候找到比他大的数是不走的,所以只能用while。
if (arr[l] < arr[r]) { //l后续不会交换,所以用来做遍历下标
swap(arr, ++less, l++); //这里一定要小心
} else if (arr[l] > arr[r]) {
swap(arr, --more, l);//这里一定要小心,l是不动的
} else {
l++;
}
}
swap(arr, more, r); //最后一位还是与中间相等的数,所以要交换到中间去。
//more就是相等数的最后一位,但是less是中间相等数的前一位,下一步返回边界要小心
return new int[] { less, more+1 }; //返回中间相等的上下边界,返回回去后面直接对左右部分同样处理。
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
public static void main(String [] args) {
System.out.println("hello");
int [] arr = new int [] {5,6,8,31,2};
quikSort(arr,0,arr.length-1);
for (int i = 0; i<arr.length; i++) {
System.out.print(arr[i]);
System.out.print(" ");
}
}
}
插入排序:笔记本第4页
public class insertSort {
public static void insertSort(int[] arr) {
if(arr.length<2||arr==null) return ;
for(int i = 1; i<arr.length; i++) {
for(int j = i-1; j>-1 && arr[j+1]<arr[j]; j--)//关键的地方在于这儿
// 核心思路和打牌一样,当前元素和前一个比,小就交换,交换后还要比较,所以j和j+1比,这里是关键
swap(arr,j+1,j);
}
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
public static void main(String[] args) {
int[] p = new int [] {1,5,9,3,66,8,4,3};
insertSort(p);
for(int i = 0; i<p.length;i++) {
System.out.print(p[i]);
System.out.print(" ");
}
}
}
归并排序:笔记本第6页
import java.util.Arrays;
public class mergeSort {
public static void mergeSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
mergeSort(arr, 0, arr.length - 1);
}
public static void mergeSort(int[] arr, int l, int r) {
if (l == r) {
return;
}
int mid = l + ((r - l) >> 1);//l,r中点的位置,这样写是为了防止溢出。
mergeSort(arr, l, mid);
mergeSort(arr, mid + 1, r); //左右两边排好序
merge(arr, l, mid, r); //对进来的数组进行前后半部分进行重组
// 这一步必须写在最后,因为从底部开始合并,然后合并上一步,即对数组的两半部分进行类似树的后续遍历一样
// 这样做的原因是,本层进行合并的时候,在merge前是要保证左半部分和右半部分是排好序的,所以是后续遍历
// 这一步也是剑指offer有道题是将两个排序好的链表合并为一个链表。
// 和刚刚快排很类似,进来一个数组,切成左边一组,右边一组,只要还可以切,
// 就继续切(所以有了后两步mergesort),直到不能切返回,后面多了merge步骤。
}
public static void merge(int[] arr, int l, int m, int r) {
int[] help = new int[r - l + 1];//如{3,2,4},l是0,r是2进来,长度是2-0+1=3,所以长度要分好
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]; //一定注意下标要对应原始数组的下标
}
}
public static void main(String[] args) {
int[] p = new int [] {1,5,9,3,66,8,4,3};
mergeSort(p);
for(int i = 0; i<p.length;i++) {
System.out.print(p[i]);
System.out.print(" ");
}
}
}
冒泡排序:
public class maopao {
public static void bubbleSort(int[] arr) {
if(arr==null||arr.length<2) return ;
for(int i = 0; i<arr.length;i++) {
//每一趟将最大的数放到最后,且下一趟会比上一趟少一个数比较(其实最后一趟没有必要,因为就他一个人)
for(int j = 0;j<arr.length-1-i;j++) {
if (arr[j]>arr[j+1])
swap(arr,j+1,j);
}
}
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
public static void main(String[] args) {
int[] p = new int [] {1,5,9,3,66,8,4,3};
bubbleSort(p);//bubble冒泡
for(int i = 0; i<p.length;i++) {
System.out.print(p[i]);
System.out.print(" ");
}
}
}
选择排序:
import java.util.Arrays;
public class Code_02_SelectionSort {
public static void selectionSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
for (int i = 0; i < arr.length - 1; i++) { //因为j=i+1
int minIndex = i;
// 从0位置开始,每一趟找一个最小的数,放在该趟对应的下标处
for (int j = i + 1; j < arr.length; j++) {
minIndex = arr[j] < arr[minIndex] ? j : minIndex;
//记录最小位置的下标,这样减少交换次数。
}
swap(arr, i, minIndex); //这一趟走完,才把这一趟对应位置的数换成后半部分最小的数。
}
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
public static void main(String[] args) {
int[] p = new int [] {1,5,9,3,66,8,4,3};
selectionSort(p);//bubble冒泡
for(int i = 0; i<p.length;i++) {
System.out.print(p[i]);
System.out.print(" ");
}
}
}
堆排序:笔记本11页
import java.util.Arrays;
public class Code_03_HeapSort {
// 将数组排序转换为二叉树形式,然后通过大根堆调整得到数组的排序
public static void heapSort(int[] arr) {
//第一步判断数组
if (arr == null || arr.length < 2) {
return;
}
//第二步建立大根堆:heapInsert
// 遍历每一个节点,如果比父节点大,则交换--->建立大根堆
for (int i = 0; i < arr.length; i++) {
heapInsert(arr, i);
}
// 第三步:大根堆只保证父比子大,无法保证左右,所以通过不断的让父节点去堆尾节点,然后调整实现排序
int size = arr.length;
swap(arr, 0, --size); //头尾交换 (不可以和while合并写循环第一条?)
while (size > 0) {
heapify(arr, 0, size); //调 大根堆
swap(arr, 0, --size); // 头尾交换,并尾部往前移
}
}
public static void heapInsert(int[] arr, int index) {
while (arr[index] > arr[(index - 1) / 2]) { //若比父节点大则交换,(index - 1) / 2当前节点的父节点
// 和插入一样,交换后也许还是大,所以要一直交换,知道不用交换为止
swap(arr, index, (index - 1) / 2);
index = (index - 1) / 2;
}
}
// 每次将大根堆放到尾部后,头结点是比较小的,然后头结点和子节点的交换,一直交换到上一步最尾部的上一个数
public static void heapify(int[] arr, int index, int size) {
int left = index * 2 + 1;
while (left < size) { //看是否越界在叶子节点上
// left + 1 就是右孩子,下一句是右孩子不越界,且三目运算返回最大孩子的下标
// 若右节点越界则返回左结点的值(即没有右节点)
int largest = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;
// 这一句是我和孩子谁大(上一步找到最大的孩子下标),谁大下标给largest
largest = arr[largest] > arr[index] ? largest : index;
// if条件表示,节点变小后但仍然比孩子都大,则不用往下沉
if (largest == index) {
break;
}
swap(arr, largest, index);
index = largest; //头结点变大后,交换的节点还要继续往下沉,让头结点=index
left = index * 2 + 1;
}
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
public static void main(String[] args) {
int[] p = new int [] {1,5,9,3,66,8,4,3};
heapSort(p);//bubble冒泡
for(int i = 0; i<p.length;i++) {
System.out.print(p[i]);
System.out.print(" ");
}
}
二分查找特别重要,且其他题目中出现排序的数组就要想下是不是可以用二分查找。
public class erfenchazhao {
public int solve(int[] arr,int target) {
if(arr==null) return -1;
if(arr.length==1&&arr[0] == target) return target;
if(arr.length==1) return -1;
if(target>arr[arr.length-1]||target<arr[0]) return -1;
//上面都是为容错而定义的
return erfen(arr,0,arr.length-1,target);
}
public int erfen(int[] arr,int l,int r,int target) {
while(l<=r) {
//这里必须有等号,因为mid+1或者-1传递给下一次的l,r时
//l,r指的是同一个值,没有等号的话就无法进入,导致查找失败。
//注意二分查找一定针对的是有序数组,且看到有序数组就想下是不是可以使用二分查找来做。
int mid = l+(r-l)/2; //如果两个数很大的话,两者相加会溢出变成负数,这样就都是负数了
if(arr[mid]>target)
r = mid -1;
else if(arr[mid]<target)
l = mid +1;
else return arr[mid];
}
return -1;
}
public static void main(String[] args) {
erfenchazhao aa = new erfenchazhao();
int [] arr = {1,5,6,9,10,16,28,37};
System.out.println(aa.solve(arr,6));
}
}
整理于:
https://mp.weixin.qq.com/s?__biz=MzIwNTc4NTEwOQ==&mid=2247485073&idx=2&sn=367c47435e3a840c74ce71f7be041cde&scene=21#wechat_redirect
面试常考的常用数据结构与算法:https://blog.csdn.net/zwj1030711290/article/details/70224852
https://www.cnblogs.com/onepixel/articles/7674659.html 排序算法这个上面总结的很好。
排序算法的一点点应用-海量数据处理,这个总结的好:
https://blog.csdn.net/v_JULY_v/article/details/7382693