8大排序学习(面试必备手写)
3个基本排序
冒泡排序
public static void BubbleSort(int[] arr){
int temp = 0;
for(int i = 0;i < arr.length - 1;i++){
for(int j = i + 1;j < arr.length;j++){
if(arr[i] > arr[j]){
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
}
选择排序
public static void selectSort(int[] arr){
for(int i = 0;i < arr.length - 1;i++){
int min = arr[i];
int minIndex = i;
for(int j = i + 1;j < arr.length;j++){
if (min > arr[j]){
min = arr[j];
minIndex = j;
}
}
if (minIndex != i){
arr[minIndex] = arr[i];
arr[i] = min;
}
}
}
插入排序
public static void insertSort(int[] arr){
int insertVal = 0;
int index = 0;
for(int i = 1;i < arr.length;i++){
insertVal= arr[i];
index= i - 1;//从该位的前一位开始比较
// if (arr[i] < arr[i - 1]){
while (index >= 0 && insertVal < arr[index]){
arr[index + 1] = arr[index];
index--;
}
// if(index + 1 != i){
arr[index + 1] = insertVal;
// }
// }
}
}
进阶排序
希尔排序
//希尔排序的交换法
public static void shellChange(int[] arr){
int temp = 0;
for(int gap = arr.length/2;gap > 0;gap /= 2){
for(int i = gap;i < arr.length;i++){
for (int j = i - gap;j >= 0;j -= gap){
if (arr[j] > arr[j + gap]){
temp = arr[j];
arr[j] = arr[j + gap];
arr[j + gap] = temp;
}
}
}
}
}
//希尔排序的移动法
public static void shellMove(int[] arr){
for(int gap = arr.length / 2;gap > 0;gap /= 2){
for(int i = gap;i < arr.length;i++){
int index = i - gap;
int insertVal = arr[i];
while (index >= 0 && insertVal < arr[index]){
arr[index + gap] = arr[index];
index -= gap;
}
arr[index + gap] = insertVal;
}
}
}
快速排序
public static void quickSort(int[] arr,int left,int right){
int pivot = arr[(left + right)/2];
int l = left;
int r = right;
int temp = 0;//临时变量
while(l < r){
while (arr[l] < pivot){
l++;
}
while (arr[r] > pivot){
r--;
}
if(l >= r){
break;
}
temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
if(arr[l] == pivot){
r--;
}
if(arr[r] == pivot){
l++;
}
}
if (l == r){
l++;
r--;
}
if (left < r){
quickSort(arr,left,r);
}
if (right > l){
quickSort(arr,l,right);
}
}
归并排序
//分+合方法
public static void mergeSort(int[] arr,int left,int right,int[] temp){
if(left < right){
int mid = (left + right) / 2;
//向左递归进行分解
mergeSort(arr,left,mid,temp);
//向右递归进行分解
mergeSort(arr,mid + 1,right,temp);
//合并
mergeSort(arr,left,mid,right,temp);
}
}
/**
*
* @param arr 排序的原始数组
* @param left 左边有序序列的初始索引
* @param mid 中间索引
* @param right 右边索引
* @param temp 做中转的数组
*/
public static void mergeSort(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){
if(arr[i] <= arr[j]){
temp[t] = arr[i];
i++;
t++;
} else {
temp[t] = arr[j];
j++;
t++;
}
}
//(二)
//把有剩余数据的一边的数据依次全部填充到temp
while (i <= mid){
temp[t] = arr[i];
i++;
t++;
}
while (j <= right){
temp[t] = arr[j];
j++;
t++;
}
//(三)
//将temp数组的元素拷贝到arr
//注意,并不是每次都拷贝所有
t = 0;
int tempLeft = left;
//
while (tempLeft <= right){
arr[tempLeft] = temp[t];
t++;
tempLeft++;
}
}
基数排序
public static void radixSort(int[] arr){
//首先,第一步,需要求得所有数中的最大值
int max = arr[0];//我先假设arr[0]为最大的值
for(int i = 0;i < arr.length;i++){
if(max < arr[i]){
max = arr[i];
}
}
//循环完后,得到了最大值,就可以通过这个数算出最大的数的位数
int weiShu = (max + "").length();
//而位数,就是基数排序大循环的次数:每次,就是对应每位的运算。
//运算之前,需要造10个桶,故:0-9,表示位数
int[][] bucket =new int[10][arr.length];
//bucketCount用来记录每个位数的桶上的存储数量
int[] bucketCount = new int[10];
for(int i = 0,n = 1;i < weiShu;i++,n *= 10){
//1.首先需要将原来数组中的所有值装进对应的桶之中(按照每个循环对应的位数)
for(int j = 0;j < arr.length;j++){
int bitCount = arr[j] / n % 10;
bucket[bitCount][bucketCount[bitCount]] = arr[j];
bucketCount[bitCount]++;
}
int index = 0;
//2.然后,将桶中的数,按照规则排序回原来的数组。
for(int j = 0;j < bucket.length;j++){
if(bucketCount[j] != 0){
for(int z = 0;z < bucketCount[j];z++){
arr[index++] = bucket[j][z];
//将bucket置零,下次排序才能进行
bucket[j][z] = 0;//可有可无
}
}
//将bucketCount置零,下一次排序才能进行
bucketCount[j] = 0;
}
}
}
堆排序(前置条件:顺序存储二叉树,堆)
public static void heapSort(int[] arr){
int temp = 0;
//将无序序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆
for (int i = arr.length/2 - 1;i >= 0;i--){
heapSort(arr,i,arr.length);
}
//将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;
//重新调节结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,
// 反复执行调整 + 交换步骤,直到整个序列有序。
for (int j = arr.length - 1;j > 0;j--){
temp = arr[j];
arr[j] = arr[0];
arr[0] = temp;
heapSort(arr,0,j);
}
}
/**
* 功能:完成 将 以 i 对应的非叶子节点的树调整成大顶堆
* 举例: int[] = {4,6,8,5,9}; => i = 1 => adjustHeap => 得到{4,9,8,5,6}
* 如果我们再次调用 adjustHeap 传入的是i = 0 => 得到{4,9,8,5,6} => {9,6,8,5,4}
* @param arr 待调整的数组
* @param i 表示非叶子节点在数组中索引
* @param length 表示对多少个元素继续调整,length 是在逐渐的减少
*/
public static void heapSort(int[] arr,int i,int length){
int temp = arr[i];//先取出当前元素的值,保存在临时变量
//开始调整
//1. k = i * 2 + 1 k 是 i节点的左子节点
for (int k = i * 2 + 1;k < length;k = k * 2 + 1){
if (k + 1 < length && arr[k] < arr[k + 1]){//说明左子节点的值小于右子节点的值
k++;//k 指向右子节点
}
if (arr[k] > temp){//如果子节点大于父节点
arr[i] = arr[k];//把较大的值赋给当前节点
i = k;//!!! i 指向k,继续循环比较
} else {
break;
}
}
//当for 循环结束后,我们已经将以i 为父节点的树的最大值,放在了 最顶(局部)
arr[i] = temp;//将temp值放到调整后的位置
}