zoukankan      html  css  js  c++  java
  • 十大排序算法

    选择排序

      选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。 

     

    public class SelectTest {
        
        public static void main(String[] args) {
            //{1,2,3,4,5}有序数组
            int arrays[]={9,6,2,3,5};//任意一个无序数组
            //int arrays[]={1,2,3,4,5};
            select_sort(arrays);
            for (int i = 0; i < arrays.length; i++) {
                System.out.print(arrays[i]+" ");
            }
        }
        
        //实现选择排序的函数
        /**
         * 选择要注意的特点:整体比较的次数为数组的长度-1 
         *    原因是最后的元素无需比较,就已经是最大的元素值了
         * @param arrays
         */
        public static void select_sort(int arrays[]){
            //整体的比较次数
            for (int i = 0; i < arrays.length-1; i++) {
                //找一个最小的元素下标
                int minIndex=i;
                for (int j = i+1; j < arrays.length; j++) {
                     //如果在数组的剩余元素中 还存在着比MinIndex对应更小的元素
                     //将minIndex的值重新赋值 
                     if(arrays[j]<arrays[minIndex]){
                        minIndex=j; 
                     }
                }
                if(minIndex!=i){//不满足此条件证明arrays[i]已经是最小的元素值了 不发生交换
                    System.out.println("hello");
                    //元素值交换的过程
                    int temp=arrays[i];
                    arrays[i]=arrays[minIndex];
                    arrays[minIndex]=temp;
                }
            }
        }
    }

    插入排序

      插入排序:以数组左边的第一个元素视为有序列表,将右侧剩余的元素进行插入操作
       如果插入的第一个元素比左侧的元素值要小 那么就将该元素的值放置到最左侧

       

    public class InsertSort {
        public static void main(String[] args) {
            //{1,2,3,4,5}有序数组
            int arrays[]={9,6,2,3,5};//任意一个无序数组
            //int arrays[]={1,2,3,4,5};
            insert_sort(arrays);
            for (int i = 0; i < arrays.length; i++) {
                System.out.print(arrays[i]+" ");
            }
        }
        /**
         * 外层循环第一次执行
         *    i=1 k=0(有序列表)
         *    temp=6 
         *    arrays[k]=9  {9,6,2,3,5} 后移过的结果 {9,9,2,3,5}
         *    k-- k=-1  k+1
         *    1 声明临时变量 保存无序列表中的第一个元素的值
         *    2 临时变量和有序列表中的元素进行对比(全部对比) 找到了要插入的位置
         *    3 真正的插入操作
         *    
         * @param arrays
         */
        private static void insert_sort(int[] arrays) {
            //条件需要改吗?
            for (int i = 1; i < arrays.length; i++) {
                //第一次要区分有序部分和无序部分 将数组下表为0的元素视为有效元素 
                //后续的元素:无序元素
                int k=i-1;//当前元素的前一个元素的下标 
                int temp=arrays[i];//将要比较的变量放置到临时变量中
                for (; k>=0&&arrays[k]>temp;k--) {
                    //元素后移的操作
                    arrays[k+1]=arrays[k];
                }
                arrays[k+1]=temp;//插入动作
            }
        }
    }

    冒泡排序

      冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

    • 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
    • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
    • 针对所有的元素重复以上的步骤,除了最后一个;
    • 重复步骤1~3,直到排序完成。
    • function bubbleSort(arr) {
          var len = arr.length;
          for (var i = 0; i < len - 1; i++) {
              for (var j = 0; j < len - 1 - i; j++) {
                  if (arr[j] > arr[j+1]) {        // 相邻元素两两对比
                      var temp = arr[j+1];        // 元素交换
                      arr[j+1] = arr[j];
                      arr[j] = temp;
                  }
              }
          }
          return arr;
      }

    希尔排序

      1959年Shell发明,第一个突破O(n2)的排序算法,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序

      

    function shellSort(arr) {
        var len = arr.length;
        for (var gap = Math.floor(len / 2); gap > 0; gap = Math.floor(gap / 2)) {
            // 注意:这里和动图演示的不一样,动图是分组执行,实际操作是多个分组交替执行
            for (var i = gap; i < len; i++) {
                var j = i;
                var current = arr[i];
                while (j - gap >= 0 && current < arr[j - gap]) {
                     arr[j] = arr[j - gap];
                     j = j - gap;
                }
                arr[j] = current;
            }
        }
        return arr;
    }

    计数排序

      计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。 

        1.找出待排序的数组中最大和最小的元素;

        2.统计数组中每个值为i的元素出现的次数,存入数组C的第i项;

        3.对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加);

        4.反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1

      

    public class CountSortTest {
        public static void main(String[] args) {
            // 长度为20的0~10之间的随机数组
            int arrays[] = { 9, 8, 2, 3, 5, 4, 9, 7, 1, 10, 0, 6, 9, 7, 10, 8, 3,
                    2, 1, 4 };
            countSort(arrays);
            for (int i = 0; i < arrays.length; i++) {
                System.out.print(arrays[i]+" ");
            }
        }
    
        private static void countSort(int[] arrays) {
            //真正实现计数排序逻辑
            int len=arrays.length; //20
            int max=arrays[0];//将数组中的第一个元素视为最大值
            for (int i = 1; i < len; i++) { //找到数组中真正的那个最大值
                if(max<arrays[i]){
                    max=arrays[i];//打擂思想
                }
            }
            //创建一个下标为从0~10这样的数组 长度为11
            int nums[]=new int[max+1];
            //arrays数组中的每个元素都是nums数组的下标
            //nums=[1, 2, 2, 2, 2, 1, 1, 2, 2, 3, 2]
            for (int i = 0; i < arrays.length; i++) {
                nums[arrays[i]]++;//nums[9]++ 三次  nums[9] 0==>3
            }
            int k=0;//作为我们一会的迭代变量 i 0~10
            //外层循环变量:索引 随机数组中的元素
            for (int i = 0; i < nums.length; i++) {
                //内层循环变量:nums数组的元素 次数 
                for (int j = nums[i]; j >0; j--) {
                    //k++:++是写在后面的 先操作 再加
                    arrays[k++]=i;//将无序数列覆盖为有序数列
                }
            }
        }
    }

    快速排序

      什么是快速排序:和归并排序稍微有点类似 也是在这里要获取中间值
       基于:中轴元素(保证在中轴元素左侧 所有的元素均小于该中轴元素
       保证在中轴元素的右侧 所有的元素均大于该中轴元素)

      

    public class QuickSortTest {
        public static void main(String[] args) {
            int arrays[]={1,3,5,7,2,4,6,8};//要排序的数组
            quickSort(arrays,0,arrays.length-1);
            for (int i = 0; i < arrays.length; i++) {
                System.out.print(arrays[i]+" ");
            }
        }
        /**
         * @param arrays:要排序的数组
         * @param left:左边界
         * @param right:右边界
         * 停止递归的条件:在左右边界完全相等的情况下 证明数组只剩下一个元素了 
         *             其必定是中轴元素 (有序)
         */
        private static void quickSort(int[] arrays,int left,int right) {
            if(left<right){
                //编写一个方法: 1 能够找到中轴元素放在合适的位置上 2 返回中轴元素对应的下标位置
                int middle=getMiddle(arrays,left,right);
                //递归操作
                quickSort(arrays, left, middle-1);
                quickSort(arrays, middle+1, right);
            }
        }
        private static int getMiddle(int[] arrays, int left, int right) {
            //1:默认选择一个元素 作为数组中的中轴元素(左边界的第一个值)
            int middle=arrays[left];
            //2:从默认的中轴元素后的第一个元素开始寻找小于中轴元素的序列
            int i=left+1;
            //3:从数组末尾的元素寻找比中轴元素大的元素
            int j=right;
            // 情况:巧合(恰好选择的中轴元素是最大的)i<=j下标越界的问题
            //     巧合(恰好选择的中轴元素是最小的) 中轴元素位置不动 
            while(true){
                while(i<=j&&arrays[i]<middle) i++;
                while(i<=j&&arrays[j]>middle) j--;    
                if(i>=j)break;
                //防止的意外情况:中轴元素后的第一个元素本身就比他大 获取比它小的元素进行位置交换
                int temp=arrays[i];
                arrays[i]=arrays[j];
                arrays[j]=temp;
            }
            //实现元素交换 把中轴元素middle放在该放的位置上
            arrays[left]=arrays[j];
            arrays[j]=middle;
            return j;
        }
    }

    归并排序

      归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。    

        1.把长度为n的输入序列分成两个长度为n/2的子序列;

        2.对这两个子序列分别采用归并排序;

        3.将两个排序好的子序列合并成一个最终的排序序列。

      

    public class MergeSortTest {
         public static void main(String[] args) {
             //局部数组1和局部数组2都必须是有序的
             //[1]和[2] [1,2] 什么时候不能排 left=right left=0 right=1
             //[1,2,3,5,7]和[4,6,8,10]=1 2 3 4 5 6 7 8 10 
             //int arrays[]={1,2,3,5,7,4,6,8,10};//是由两个局部数组构成的大数组
             int arrays[]={7,2,3,5,6,1,10};//不是规则数组 递归
             dg(arrays,new int[arrays.length],0,arrays.length-1);
             for (int i = 0; i < arrays.length; i++) {
                 System.out.print(arrays[i]+" ");
             }
         }
         public static void dg(int arrays[],int temp[],int left,int right){
              //middle的值是通过自行计算的 left=right的情况下 只剩下一个了 有序 进行归并
              int middle=(left+right)/2;
              if(left<right){ 
                  //实现递归操作
                  dg(arrays,temp,left,middle); //遍历数组左侧的值
                  dg(arrays,temp,middle+1,right);//遍历右侧的值
                  //直到变成元素个数为1的数组的情况下 归并操作 
                  mergeSort(arrays,temp,left,middle,right);
              }
         }
        /**
         * 在没有做递归的情况下 : left=0 right=length-1 0 right=middle
         * 注意递归问题:左右边界的开始
         * @param arrays:要排序的数组
         * @param temp:临时数组 存放已排序好的元素
         * @param left:左边界
         * @param middle:分割边界
         * @param right:右边界
         * @return
         */
        private static void mergeSort(int[] arrays, int[] temp, int left, int middle, int right) {
            //i:局部数组1的下标起始位置  j:局部数组2的下标的起始位置
            int i=left,j=middle+1;
            //递归情况下 要不断 以左边界的位置开始 到右边界结束
            for (int k =left; k<=right; k++) {
                //总共会有四种情况
                /**
                 * 为什么是小于等于:稳定排序(排序后元素的位置并没有发生改变)
                 * i++:将++操作写在后面 先赋值再累计
                 */
                if(i>middle){//如果左边的数组的元素已取完 则拼接右侧数组剩余的元素
                    temp[k]=arrays[j++];
                }else if(j>right){ //如果右边的数组的元素已取完 则拼接左侧数组剩余的元素
                    temp[k]=arrays[i++];
                }else if(arrays[i]<=arrays[j]){
                    temp[k]=arrays[i++];//把较小的元素放置到临时数组
                }else{
                    temp[k]=arrays[j++];
                }
            }
            //temp已被排序好了 从左边距开始 一直到右边距 对原有数组元素的值进行覆盖
            for (int k = left; k <=right; k++) {
                arrays[k]=temp[k];//把排序好的值覆盖到原数组
            }
        }
         
         
    }

    桶排序

      桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。

      

    public class BucketSortTest {
        public static void main(String[] args) {
            double arrays[] = { 4.5, 3.14, 2.56, 2.02, 0.5};// 长度为5的随机数组
            bucket_sort(arrays);
            for (int i = 0; i < arrays.length; i++) {
                System.out.print(arrays[i] + " ");
            }
        }
    
        private static void bucket_sort(double[] arrays) {
            //声明了最大值和最小值
            double max=arrays[0];
            double min=arrays[0];
            for (int i = 0; i < arrays.length; i++) {
                if(max<arrays[i])
                    max=arrays[i];
                if(min>arrays[i])
                    min=arrays[i];
            }
            //获取一下两者的差值
            double sub=max-min;
            //声明一下桶的数量 
            int bucketNum=arrays.length;
            //创建数据结构了  二维集合 一个ArrayList 我们把ArrayList集合中的LinkedList作为每一个桶
            //声明集合中元素的个数为bucketNum
            ArrayList<LinkedList<Double>> lists=new ArrayList<LinkedList<Double>>(bucketNum);
            
            //初始化一下
            for (int i = 0; i < bucketNum; i++) {
                  lists.add(new LinkedList<Double>());
            }
            //向桶中放置元素 思路?
            for (int i = 0; i < arrays.length; i++) {
                //随机元素:arrays[i]
                //获取随机元素应该放置的下标位置 int 
                int index=(int)((arrays[i]-min)/(sub/(bucketNum-1)));
                //插入操作
                lists.get(index).add(arrays[i]);
            }
            
            //对桶进行局部排序 LinkedList Collections.sort()
            for (int i = 0; i < lists.size(); i++) {
                Collections.sort(lists.get(i));//局部排序
            }
            int k=0;
            //输出回原数组
            for (LinkedList<Double> linkedList : lists) {
                for (Double item : linkedList) {//一个桶中可能保存了多个元素值
                    //使用有序数列覆盖无序数列
                    arrays[k++]=item;
                }
            }
        }
    }

    基数排序

      基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。

        1.取得数组中的最大数,并取得位数;

        2.arr为原始数组,从最低位开始取每个位组成radix数组;

        3.对radix进行计数排序(利用计数排序适用于小范围数的特点);

      

    var counter = [];
    function radixSort(arr, maxDigit) {
        var mod = 10;
        var dev = 1;
        for (var i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
            for(var j = 0; j < arr.length; j++) {
                var bucket = parseInt((arr[j] % mod) / dev);
                if(counter[bucket]==null) {
                    counter[bucket] = [];
                }
                counter[bucket].push(arr[j]);
            }
            var pos = 0;
            for(var j = 0; j < counter.length; j++) {
                var value = null;
                if(counter[j]!=null) {
                    while ((value = counter[j].shift()) != null) {
                          arr[pos++] = value;
                    }
              }
            }
        }
        return arr;
    }

    堆排序

      堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

      

    var len;    // 因为声明的多个函数都需要数据长度,所以把len设置成为全局变量
     
    function buildMaxHeap(arr) {   // 建立大顶堆
        len = arr.length;
        for (var i = Math.floor(len/2); i >= 0; i--) {
            heapify(arr, i);
        }
    }
     
    function heapify(arr, i) {     // 堆调整
        var left = 2 * i + 1,
            right = 2 * i + 2,
            largest = i;
     
        if (left < len && arr[left] > arr[largest]) {
            largest = left;
        }
     
        if (right < len && arr[right] > arr[largest]) {
            largest = right;
        }
     
        if (largest != i) {
            swap(arr, i, largest);
            heapify(arr, largest);
        }
    }
     
    function swap(arr, i, j) {
        var temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
     
    function heapSort(arr) {
        buildMaxHeap(arr);
     
        for (var i = arr.length - 1; i > 0; i--) {
            swap(arr, 0, i);
            len--;
            heapify(arr, 0);
        }
        return arr;
    }
  • 相关阅读:
    潜水员(二维DP)
    开餐馆(OJ 6045)
    石子归并(区间DP)
    庆功会(多重背包)
    JavaScript案例三:动态显示时间
    JavaScript案例二:在末尾添加节点
    JavaScript案例一:Window弹窗案例
    JavaScript BOM对象介绍
    JavaScript模拟函数重载
    MapReduce作业和任务
  • 原文地址:https://www.cnblogs.com/wnwn/p/11995365.html
Copyright © 2011-2022 走看看