选择排序

  选择排序(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;
}
 posted on 2019-12-06 15:08  wnwn  阅读(203)  评论(0编辑  收藏  举报