> 文章列表 > 八大排序算法(冒泡排序、快速排序、堆排序.....)

八大排序算法(冒泡排序、快速排序、堆排序.....)

八大排序算法(冒泡排序、快速排序、堆排序.....)

每坚持一天,offer就会离我更近一步🌹

文章目录

    • 冒泡排序
    • 选择排序
    • 插入排序
    • 希尔排序
    • 快速排序
    • 计数排序
    • 堆排序
    • 归并排序

冒泡排序

算法描述:从第一个元素开始,两两比较,如果前者比后者大,那么就将两者进行交换,这样每经过一次排序,都能找到一个最大的元素并且把它放在数组的最后。
稳定性:稳定
时间复杂度O(N^2)
代码:

public static int[] bubbleSort(int[] arr){for (int i = 0; i < arr.length - 1; i++) {
//            比较次数要减去i,每比较一次都会把最大的排到最后for (int j = 0; j < arr.length - 1 - i; j++) {
//                如果前边元素比后边的元素大就交换if(arr[j+1] < arr[j]){int temp = arr[j+1];arr[j+1] = arr[j];arr[j] = temp;}}}return arr;}

选择排序

算法描述:在每一次排序时,先假设第一个元素是最小的,然后从第二个元素一直遍历到最后一个元素,如果找到比第一个小的元素就进行交换,否则不交换。第一次排序时,有序区间中只有一个元素;第二次排序,有序区间中有两个元素,依次递增,直到所有元素都有序
时间复杂度:O(N^2)
稳定性:不稳定
代码:

public static void selectSort(int[] arr){for(int i = 0;i < arr.length - 1;i++){
//            假设第一个元素是最小的int minIndex = i;for (int j = i+1; j < arr.length; j++) {
//                再从无序的元素中找到比arr[minIndex]小的元素,进行交换if (arr[j]<arr[minIndex]){int temp = arr[j];arr[j] = arr[minIndex];arr[minIndex] = temp;}}}}

插入排序

算法描述:,初始时,先把第一个元素看成是有序的,然后把未排序的元素一个一个插入到有序序列中。
时间复杂度:O(N^2)
稳定性:稳定

public static void insertSort(int[] arr){
//        将arr[0]看作是有序的,所以从arr[1]开始遍历for (int i = 1; i < arr.length; i++){
//        暂存待插入元素int inserted = arr[i];int j = i - 1;
//            从后往前开始比较,如果待插入元素更小就将有序元素后移for (; j >= 0 && inserted < arr[j]; j--) {arr[j+1] = arr[j];}
//        将待插入元素插入arr[j+1] = inserted;}}

希尔排序

改进了插入排序

public static void shellSort(int[] arr){int n = arr.length;for(int gap = n/2;gap > 0; gap /= 2){for (int i = gap; i < n; i++) {int inserted = arr[i];int j=i-gap;for (; j >= 0&&arr[j]>inserted; j-=gap) {arr[j+gap] = arr[j];}arr[j+gap] = inserted;}}}

快速排序

算法描述:选择第一个元素当哨兵,一个左指针一个右指针,左指针从左开始扫描,遇到比哨兵大的元素就停;右指针从右开始扫描,遇到比哨兵小的元素就停,然后交换两个元素,直到左指针和右指针相遇,并交换相遇处的元素和哨兵。然后分别进行左半部分和右半部分的排序,同样的过程。
时间复杂度:O(NlogN)
稳定性:不稳定
代码:

public static void quickSort(int[] arr,int begin,int end){if (begin > end) return;
//        第一个元素当作哨兵int pivot = arr[begin];int i = begin;int j = end;while (true){
//            从后往前找比哨兵小的while (arr[j] >= pivot && i < j)j--;
//            从前往后找比哨兵大的while (arr[i] <= pivot && i < j)i++;
//            两个指针相遇就暂停if (i >= j){break;}
//            指针相遇后交换元素int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}
//          交换哨兵和指针相遇处的元素arr[begin] = arr[i];arr[i] = pivot;
//        对左半部分元素进行排序quickSort(arr,begin,i-1);
//        对右半部分元素进行排序quickSort(arr,i+1,end);}

计数排序

算法描述:从初始数组中选取一个最大的元素,用它来做辅助数组的长度,然后遍历初始数组,统计每一个元素出现的次数并保存到辅助数组中,然后遍历辅助数组,取出元素并覆盖初始数组即可。
时间复杂度:O(N)
空间复杂度:O(N)
适用于元素范围较小的数组
代码:

public static void countSort(int[] arr){int max = Integer.MIN_VALUE;
//        找出数组中最大的数for(int num:arr){if(num > max) max = num;}
//      初始化计数数组,统计每个元素所出现的次数int[] temp = new int[max+1];for(int i=0;i<arr.length;i++){temp[arr[i]]++;}
//      取出计数数组中的元素,覆盖原来的数组int k = 0;for(int i=0;i<temp.length;i++){for(int j = temp[i];j > 0;j--){arr[k++] = i;}}}

堆排序

算法描述:先根据给定数组建一个大根堆(小根堆也可以),然后每次取堆顶元素和堆尾元素进行交换,此时取下来的堆顶元素就是当前数组中最大的,然后再次维护堆的性质,执行n次之后数组即为有序。
时间复杂度:O(NlogN)(建堆的时间复杂度是O(N),维护堆性质的时间复杂度是O(logN)
稳定性:不稳定
代码:

//    堆排序入口public static void heapSort(int[]arr){int n = arr.length;//建立堆,大根堆//        注意,建完堆之后是局部有序的,建堆的复杂度是O(n)
//        从n/2-1开始的原因:下标为i的节点的父节点下标是(i-1)/2,当i=n-1时,代入得i=n/2-1for( int i = n/2-1;i>=0;i--){heapify(arr,n,i);}//        排序//每次取堆中最大元素并维护堆的性质for( int i=n-1;i>0;i--){int temp = arr[i];arr[i] = arr[0];arr[0] = temp;heapify(arr,i,0);}}
//        比较的具体过程public static void heapify(int[] arr,int n,int i){
//        父节点下标int largest = i;
//        左孩子下标int lson = 2 * i + 1;
//        右孩子下标int rson = 2 * i + 2;
//        比较父节点和左孩子,左孩子下标必须小于n,如果左孩子大,则替换父节点if(lson<n&&arr[largest]<arr[lson]){largest = lson;}
//        比较父节点和右孩子,右孩子下标必须小于n,如果右孩子大,则替换父节点if(rson<n&&arr[largest]<arr[rson]){largest = rson;}
//        如果不满足大根堆的性质,则进行交换
//        将父节点和左右孩子中较大的元素交换if(largest!=i){int temp = arr[largest];arr[largest] = arr[i];arr[i] = temp;
//            向下继续比较heapify(arr,n,largest);}}

归并排序

算法描述:采用递归与分治的思想,先把数组按照两两划分的原则对数组分割,直到每个分组都是一个元素,然后再按照之前分割的顺序比较大小之后进行两两合并。
时间复杂度:O(NlogN)
稳定性:稳定
代码:

public static void merge(int[] arr,int[] tempArr,int left,int mid,int right){
//        标记左半区第一个未排序的元素int l_pos = left;
//        标记右半区第一个未排序的元素int r_pos = mid + 1;
//        临时数组元素的下标int pos = left;
//        开始合并while (l_pos <= mid&&r_pos <= right){if(arr[l_pos] < arr[r_pos])tempArr[pos++] = arr[l_pos++];elsetempArr[pos++] = arr[r_pos++];}
//        可能左半区还有剩余元素while (l_pos <= mid)tempArr[pos++] = arr[l_pos++];
//        可能右半区还有剩余元素while (r_pos <= right)tempArr[pos++] = arr[r_pos++];
//        把临时数组的元素复制回主数组while (left <= right){arr[left] = tempArr[left];left++;}}public static void msort(int[] arr,int[] tempArr,int left,int right){
//        如果只有一个元素则不进行划分if(left < right){int mid = (left+right)/2;//递归划分左半部分msort(arr,tempArr,left,mid);//递归划分右半部分msort(arr,tempArr,mid+1,right);//合并merge(arr,tempArr,left,mid,right);}}public static void mergeSort(int[] arr){int n = arr.length;
//        分配一个辅助数组int[] tempArr = new int[n];
//        开始归并排序,传入左边界和右边界msort(arr,tempArr,0,n-1);}

在这里插入图片描述
整理也挺费时间的,如果觉得对你有帮助,点个赞再走吧!感谢收看!