常见排序(预习)

排序:

稳定性

待排序的记录中,存在相同的关键字,排序后,关键字的相对次序不变,这就是一个稳定的排序.

 

内部排序在内存中 ,外部排序在外存中.

直接插入排序

简介:

基本操作是将一条记录插入到已排好的有序表中,从而得到一个新的、记录数量增1的有序表

默认将要插入的表是有序表

默认第一个数是有序的,第二个数要插入到有序表,和有序表后面的数字进行比较,插入到合适的位置.

在这里插入图片描述

 public static List<Integer> insertSort(int[] arr){
         for (int i = 1; i < arr.length ; i++) {
             int temp = arr[i];
             int j;
             for ( j = i-1; j >= 0; j--) {
                             if(arr[j] > temp){
                             arr[j+1] = arr[j];
                             }else {
                             break;
                             }
             }
              arr[j+1] = temp;
         }
         return list;
     }

时间复杂度O(n^2)

时间复杂度O(1)

稳定的排序

希尔排序:

希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本

希尔排序是一种基于插入排序的排序算法,其核心思想是将整个待排序序列分成若干个子序列进行插入排序,然后依次缩短子序列的长度,直到最后子序列长度为1,完成对整个序列的排序。

img

 public static int[] shellSort(int[] a){
         int gap = a.length;
         while (gap > 1){
             gap /=2;
             shell(a,gap);
         }
         shell(a,1);
         return a;
     }
 ​
     private static void shell(int[] a, int gap) {
         for (int i = gap; i <a.length ; i++) {
             int temp = a[i];
             int j;
             for ( j = i-gap; j >=0 ; j-=gap) {
                 for(temp < a[j])
                     a[j+gap] = a[j];
             } else{
             braek;
             }
             a[j+gap] = temp; 
         }
     }

时间复杂度O(N^1.3)

不稳定的排序

选择排序:

从一组数据中找到最小或者最大的数据,放在初始位置.直到全部排好序列.

选择排序

待排序的记录中,存在相同的关键字,排序后,关键字的相对次序不变,这就是一个稳定的排序.

 public vois selectSort(int[] arr){
         for (int i = 0; i < arr.length; i++) {
             int min = arr[i];
             int j;
             for (int j = i+1; j < arr.length; j++) {
                 if (arr[j] < min){
                     swap(arr,j,min);
                 }
             }
         }
     }
     public void swap(int[] arr,int j,int t){
         int tmp = arr[j];
         arr[j] = arr[t];
         arr[t] = tmp;
     }

堆排序:

过程:(https://mp.csdn.net/mp_blog/creation/editor/130708844)

动画:堆排序动画演示哔哩哔哩bilibili

将一组数据从小到大排序:

使用大根堆,以此类推.

使用小根堆左右孩子不能保证谁打谁小.

  public void heapSort(){
          int end = usedSize-1;  //记录下标
          while (end > 0){
              swap(elem,0,end);//交换堆顶和最后一个元素
              shitfDown(0,end);堆顶元素向下调整
              end--;//除去排好序的元素
          }
           public void createHeap() {
         for (int parent = (usedSize - 1 - 1) / 2; parent >= 0; parent--) {
             //usedSize-2: -1是因为下标 再-1是因为计算parent的值就是(i-1)/2
             shitfDown(parent, usedSize);//每棵树向下调整
         }
     }
      public void shitfDown(int parent, int usedSize) {
         int child = 2 * parent + 1;
         while (child < usedSize) { //最起码要有左孩子
             if (child + 1 < usedSize && elem[child + 1] > elem[child]) {
                 child++;//判断左右孩子的最大值
             }
             if (elem[child] > elem[parent]) {
                 swap(elem, child, parent);//调整完一次  之后继续调整这棵树
                 parent = child;
                 child = 2 * parent + 1;
             } else {
                 break;//既然这是个大根堆  那就不用调整了,因为大根堆的子堆一定是大根堆
             }
 ​
         }
     }
    public void swap(int[] elem, int child, int parent) {
         int tmp = elem[child];
         elem[child] = elem[parent];
         elem[parent] = tmp;
     }

冒泡排序

两两比较,找最大或者最小的.

  public void bubbleSort(int[] arr){
         for (int i = 0; i <arr.length - 1 ; i++) { //
             boolean flag = false;
             for (int j = 0; j <arr.length-1-i ; j++) { 
                         if (arr[j] > arr[j+1]){  //相邻元素进行比较  每次找到每轮最大的
                             swap(arr,j,j+1);
                            flag = true;
                         }
             }
                         if (flag == false){
                                 return;             
 }//如果没有发生交换 说明有序  直接跳出循环
               
         }
     }

时间复杂度:0(N^2)

空间复杂度O(1)

快速排序

挖坑法:

取一个元素作为基准,左边比它小,右边比它大 直到全部排序完.

在这里插入图片描述

left从做左边走,right从右面走.比如以6为例子.

把6先拿出来,right从后往前找到比6小的放前面.left找到比6大的放有空的哪个.

 

把left的元素放入right中.重复这个过程知道left和right相遇.

 

直到把6放入left和right相遇的位置.

如果先算前面,之后新的right就是这个基准-1.

  public void quickSort(int[] arr){
             quick(arr,0,arr.length-1);
         }
         public void quick(int[] arr,int left,int right){
             //为什么取大于号  1 2 3 4  right=-1了
         if (left >= right){
             return;
         }
         if(right - left + 1 <=14){
         for(int i=left;i<right;i++){
         int tmp = arr[i];
         for(int j=i-1;j>=0;j--){
         if(tmp <arr[j]){
         arr[j+1] = arr[j];
         }else{
         break;
         }
         arr[j+1] = tmp;
         }
         }
         return;
         }//如果区间小,直接插入排序
 ​
         int index = partition(arr,left,right);
 ​
         quick(arr,left,index-1);
         quick(arr,index+1,right);
         }
 挖坑:
     private int partition(int[] arr, int left, int right) {
             int tmp = arr[left];
             while (left<right){
                 while (left < right &&arr[right] >= tmp){  //如果没有等号 这就是个死循环
                     right--;
                 }       //从后往前找比基准值小的
                 arr[left]=arr[right];
                 while (left < right && arr[left] <= tmp){
                     left++;
                 }
                 arr[right]=arr[left];
             }
             arr[left] = tmp;
             return left;
     }
     Hoare法:
    
      private int partition2(int[] arr, int left, int right) {
         int tmp = arr[left];
         int i = left;
         while (left < right){
             while (left < right && arr[right] <= tmp){
                 right--;
             }
             while (left < right && arr[left] >= tmp){
                 left++;
             }
             swap(arr,right,left);
         }
         swap(arr,left,i);
         return left;
 ​
     }

归并排序

  public static void mergeSort(int[] arr){
         meregeSort(arr,0,arr.length-1);调用递归
     }
     public static void meregeSort(int[] arr,int left,int right){
         if (left >= right){ // 开始位置大于结束位置 如果只有右子树呢?
             return;
         }
         int mid = (left+right) / 2;  //计算中间位置
         meregeSort(arr,left,mid);//分组 直到只要1个数组
         meregeSort(arr,mid+1,right);
         merge(arr,left,right,mid); //排序
     }
     private static void merge(int[] arr,int start,int end,int mid){
         int s1 = start;
         int s2 = mid+1;//第二组的开始位置
         int[] tmp = new int[end-start+1]; //排好序就放在这个数组
         int k = 0; // 新数组的下标
         while (s1 <= mid && s2 <=end){//如果第一组和第二组都有元素则循环,而且两组都是有序序列
             if (arr[s1] <= arr[s2]){ 
                 tmp[k++]=arr[s1++];
             }else {
                 tmp[k++] = arr[s2++];
             }
         }
         while (s1 <=mid){  // 如果s1内有元素
             tmp[k++] = arr[s1++];
         }
         while (s2 <=end){
             tmp[k++] = arr[s2++];
         }
         for (int n = 0;n <arr.length;n++){//将排好序的数组放入要排序的数组中
             arr[i+start] = tmp[i]; //画图  每次看开始位置
         }
     }

 

非递归:

 

时间复杂度:

1三数取中:解决每次分割尽量不要使得一边为空

2小区间插入排序. 如果是一个二叉树,后两层占到70%的节点数.如果继续递归那么时间复杂度和空间复杂度就会上来.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值