常见排序算法总结思考(java实现算法)

总结回顾下几个排序算法:
参考文章:

选择排序

  • 思想:在序列中找到最小(最大)的元素,存到排序序列的起始位置,然后从剩余未排序的
  • 元素中继续寻找最小(最大)元素,放在已排序的序列的起始位置
  • 思考:为甚么叫做选择排序?因为每次都是从剩余的序列有意识选择最值元素。(从后面序列拿元素是需要比较的)
  • 算法描述
  • 初始状态:无序区为R[1…n],有序区为空
  • 第i(i=1,2,3…n-1)趟排序开始是,分为有序区R[1…i-1]和R[i…n)。
  • 该趟排序从当前无序区中选出关键字最值的记录R[K],与无序区的第一个交换
  • 新有序区为R[1…i] 新无序区R[i+1…n)
  • n-1趟结束,数组有序化了
public static int[] selectionSort(int[] array){
  if(array.length==0){
   return array;
  }
  for (int i = 0; i < array.length; i++) {
   int minIndex=i;
   for (int j = i; j < array.length; j++) {
    if(array[j]<array[minIndex]){ //遍历找到最小的值
     minIndex=j;
    }
   }
   int temp=array[minIndex];  //将在后面搜寻的数列最小值放入array[i];
   array[minIndex]=array[i];
   array[i]=temp;
  }
  return array;
 }

插入排序Insertion Sort

  • 思想:要排序的一堆数组中,假设前n-1是排好序的,现在将第n数组插入到前面已经排好序的数列中。
  • 使得这n个数组也是排好序的,如此循环,直到全部排好
  • 思考:为什么叫做插入排序,是按顺序在后面数列(未排序)拿一个数, 有意识的插入到前面已经排序的数列中(这个插入过程是需要比较的)
  • 算法描述
  • 1 从第一个元素开始,默认该元素是已经排序的
  • 2 取出下一个元素i,在已经排序的元素序列从后向前扫描
  • 3 如果某元素大于新元素i,则将该元素移到下一个位置
  • 4 重复步骤3 直到已排序的元素小于或者等于新元素i的位置
  • 5 将新元素i插入到该位置后
  • 重复2-5
 public static int[] insertionSort(int[] array){
  if(array.length==0){
   return array;
  }
  int needsort;
  for (int i = 0; i < array.length; i++) {
   needsort=array[i+1];
   int preIndex=i;
   while(preIndex>=0&&needsort<array[preIndex]){//为新元素寻找合适的位置
    array[preIndex+1]=array[preIndex];//若某个元素大于新元素的值,则将该元素向后挪位置
    preIndex--;   
   }//退出while循环时,已经为新元素找到合适的位置,即preIndeex+1
   array[preIndex+1]=needsort;
  }
  return array;
 }

希尔排序Shell Sort

  • 思想:希尔排序时插入排序的一种更高效的改进版本,将整个待排序的序列分割成若干个子序列进行插入排序,
  • 待整个序列中的记录基本有序,再进行直接插入排序。
  • 思考总结:每次先将序列分成di组 ,每间距为i的所有元素看成一个小序列,然后将若干个小序列进行组内插入排序
  • 重复以上步骤,直到di为1,此时就是直接插入排序。是再插入排序的基础上做的一些改进。
  • 算法描述:
  • 1 先取一个人正整数d1(d1<n),把全部记录分成d1个组,所有距离为d1的倍数的记录看成一个组
  • 然后再各组内进行插入排序
  • 2 然后取d2(d2<d1) 重复上述分组和排序操作;直到去di=1(i>1)位置,即所有记录成为一个组
  • 3 最后对这个组进行排序 这时候就是一个简单插入排序了
  • 一般选取d1为n/2 d2为d1/2…
public static int[] shellsort(int[] array){
  if(array.length==0){
   return array;
  }
  int len=array.length;
  int needsort,gap=len/2;  // 12 3 4 5 6 7 8 2 1 9
  while(gap>0){ //对每次按照gap分组,进行简单直接排序
   for(int i=gap; i<len;i++){    //与简单直接排序比较:gap为1 且i=0   而这里i一定为gap 因为要分脆弱干个小序列,每个小序列进行简单排序,每		  	个小序列开头索引并不是0  
    needsort=array[gap];   
    int preIndex=gap-i;  
    while(preIndex>=0&&array[preIndex]>needsort){
     array[preIndex+gap]=array[preIndex]; 
     preIndex-=gap; 
    }
    array[preIndex+gap]=needsort;
   }
   gap/=2;
  }
  return array;
 }

归并排序(Merge Sort)
*思想:分治法,思想是分而治之,归并排序是将两个有序序列合并成一个有序序列,那么对于一个无序的长序列
*分解成若干有序的子序列(直到每个子序列只有一个元素的时候),然后依次进行归并
*
*思考:就像一个完满二叉树 从下往上排序开始排序
*算法描述
*1将原始序列从中间分为左 右两个子序列,此时序列为2
*2再将左右序列再分别从中间分为左右两个子序列,此时序列数为4
*3重复以上步骤,直到每个子序列都只有一个元素,可以认为每个子序列都是有序的
*4 最后依次进行归并操作,直到序列数变为1
*


 //递归法
 public static int[] MergeSort(int[] array){ // length=10;
  if(array.length<2) return array;    //   return array 0
  int mid=array.length/2;//mid=5    2     1
  int[] left=Arrays.copyOfRange(array, 0, mid);//left 0-4     lleft=0-1  lll=0
  int[] right=Arrays.copyOfRange(array, mid, array.length);//right 5-10   lright=2-4  llr=1
  return merge(MergeSort(left),MergeSort(right)); //MergeSort(left)  M(lleft)=2  M(llleft):0
  //递归排序 MeraeSort(left)就是不断递分割序列,直到序列不可分割为止
 } 
 
 public static int[] merge(int[] left,int[] right){
  int[]result =new int[left.length+right.length];
  for (int index=0,i = 0,j=0;index < result.length; index++) {
   if (i >= left.length) //如果left长度小于i,就是left这边比较完了(或者left的1长度为0),将right的下一个元素直接纳入到数组中
    result[index] = right[j++];
   else if (j >= right.length)
    result[index] = left[i++]; 
   else if (left[i] > right[j])
    result[index] = right[j++];
   else
    result[index] = left[i++];
  }
  return result;
 }

快速排序
*思想:快速排序使用分治的思想
*
*思考:递归分区排序
*算法描述

  • 1在待排序列中,选择一个元素,作为基准
  • 2以该基准在序列中的实际位置,把序列分成左右两个子序列,左序列比基准小,右序列比基准大
  • 3递归的对两个序列进行快速排序,直到序列为空或者只有一个元素
private static int partition(int[] arr, int low, int high) {
                //指定左指针i和右指针j
                int i = low;
                int j= high;
                
                //将第一个数作为基准值。挖坑
                int x = arr[low];
                
                //使用循环实现分区操作
                while(i<j){//5  8
                        //1.从右向左移动j,找到第一个小于基准值的值 arr[j]
                        while(arr[j]>=x && i<j){
                                j--;
                        }
                        //2.将右侧找到小于基准数的值加入到左边的(坑)位置, 左指针想中间移动一个位置i++
                        if(i<j){
                                arr[i] = arr[j];
                                i++;
                        }
                        //3.从左向右移动i,找到第一个大于等于基准值的值 arr[i]
                        while(arr[i]<x && i<j){
                                i++;
                        }
                        //4.将左侧找到的打印等于基准值的值加入到右边的坑中,右指针向中间移动一个位置 j--
                        if(i<j){
                                arr[j] = arr[i];
                                j--;
                        }
                }
                
                //使用基准值填坑,这就是基准值的最终位置
                arr[i] = x;//arr[j] = y;
                //返回基准值的位置索引
                return i; //return j;
        }
        private static void quickSort(int[] arr, int low, int high) {//???递归何时结束  递归条件当不满足low<high时
                if(low < high){
                        //分区操作,将一个数组分成两个分区,返回分区界限索引
                        int index = partition(arr,low,high);
                        //对左分区进行快排
                        quickSort(arr,low,index-1);
                        //对右分区进行快排
                        quickSort(arr,index+1,high);
                }
        
        }
        public static void quickSort(int[] arr) {
                int low = 0;
                int high = arr.length-1;
                quickSort(arr,low,high);
        }

*堆排序

  • 算法思想:堆排序是选择排序的一种。是将数据看成完全二叉树,根据完全二叉树来排序的一种算法
  •  要求其节点的数值都大于或小于左右子节点的值。
    
  • 思考:堆映射的数组并不是有序数组,所以利用大小根堆的性质对数组排序。实际上是一种选择排序。
  • 算法描述:
  • 当前节点位置为i 所以父节点位置(i-1)/2 左孩子索引2i+1 右孩子索引2i+2
  • 大根堆arr(i)>arr(2i+1)&&arr(i)>arr(2i+2)
  • 小根堆arr(i)<arr(2i+1)&&arr(i)<arr(2i+2)
  • 1首先将待排序的数组构造成一个大根堆,此时,整个数组1的最大值就是堆结构的顶端
  • 2将顶端的数与末尾的数进行交换,末尾数为最大值,剩余待排序数组个数为n-1
  • 3将剩余n-1个数在构造成大根堆,再将顶端数与n-1位置的数进行交换,如此反复便能得到有序数组
 //建堆 arrays看作完全二叉树  currentRootNode当前父节点位置  size节点综述
        public static void heapify(int[] arrays,int currentRooNode,int size){
         if(currentRooNode<size){
          //左子树和右子树的位置
          int left =2*currentRooNode+1;
          int right=2*currentRooNode+2;
          
          //把当前父节点看成式最大的
          int max=currentRooNode;
          
          //开始比较父节点和左右子节点的大小
          if(left<size){ //先决条件
           //如果比当前根元素大,记录位置
           if(arrays[max]<arrays[left]){
            max=left;
           }
          }
          
          if(right<size){ //先决条件
           //如果比当前根元素大,记录为位置
           if(arrays[max]<arrays[right]){
            max=right;
           }
          }
          
          //如果最大不是根元素的位置,那么就交换
          if(max!=currentRooNode){
           //max位置为左节点或者右节点的位置
           int temp=arrays[max];
           arrays[max]=arrays[currentRooNode];
           arrays[currentRooNode]=temp;
           
           //继续比较,直到完成一次建堆
           //一般此处会有疑问,若max位置为左节点位置,右节点以及一下要不要排序了?
           //因为未比较时除了当前节点,左右子节点以及后续子节点都满足大根堆的性质,
           //若将左节点和当前节点位置交换,左节点以及后续节点可能不满足大根堆性质,而右节点仍然满足,所以不用调整。
           heapify(arrays,max,size);
          }
          
         }
        } 
        //完成一次建堆,最大值在堆的顶部
        public static void maxHeapify(int[] arrays,int size){
         //从数组的尾部开始,直到第一个元素(角标为0)
         for (int i = size-1; i >=0; i--) {
    heapify(arrays,i,size);//将剩余数组再构造成大根堆
   }
        }
        
        //堆排序算法,不断建堆,让数组最后一位与当前堆顶(数组第一位)交换即可排序
        public static void heapifySort(int[] arrays){
         for(int i=0;i<arrays.length;i++){
          //每次建堆就可以排除一个元素了
          maxHeapify(arrays,arrays.length-i);
          //交换
          int temp=arrays[0];
          arrays[0]=arrays[(arrays.length-1)-i];
          arrays[(arrays.length-1)]=temp;
         }
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值