Java数据结构常见几大排序梳理

目录
  • 一、排序的概念和分类
    • 1.排序的基本概念
    • 2.排序的稳定性
  • 二、常见排序
    • 1.直接插入排序
    • 2.希尔排序
    • 3.简单选择排序
    • 4.堆排序
    • 5.冒泡排序
    • 6.快速排序
      • 6.1.递归快速排序
      • 6.2.非递归方式实现
    • 7.归并排序
      • 7.1.递归归并排序
      • 7.2.非递归归并排序
  • 总结

一、排序的概念和分类

1.排序的基本概念

排序是将一批无序的记录(数据)重新排列成按关键字有序的记录序列的过程。

排序分为内部排序和外部排序

  • 若整个排序过程不需要访问外存便能完成,则称此类排序问题为内部排序。
  • 反之,若参加排序的记录数量很大,整个序列的排序过程不可能在内存中完成,则称此类排序问题为外部排序。

内部排序的过程是一个逐步扩大记录的有序序列长度的过程

2.排序的稳定性

假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

总结起来就是,如果一个数据在排序过程中发生了跳跃行为,则为不稳定的排序;反之,则是稳定的排序。

  • 时间复杂度:一个算法执行所耗费的时间
  • 空间复杂度:运行完一个程序所需的内存大小。

二、常见排序

1.直接插入排序

直接插入排序的基本操作是讲一个记录插入到已经排好序的有序表中,从而得到一个新的、记录数增1的有序表。

代码:

    public static void insertSort(int[] array) {
        for (int i = 1; i < array.length; i++) {
            int tmp = array[i];
            int j = i-1;
            for (; j >= 0 ; j--) {
                if(array[j] > tmp) {
                    array[j+1] = array[j];
                }else {
                    break;
                }
            }
            //j回退到了小于0的地方
            array[j+1] = tmp;
        }
    }

流程图解:

时间和复杂度分析: 我们在实现的这个排序算法的时候,只借助了一个辅助的记录空间。

所以最好的情况就是我们原来需要的排序的元素之间就是有序的,比如说{1,2,3,4,5,6},那么我们需要比较的次数,其实就是临近两个元素的比较,因此没有移动的记录,时间复杂度为O(n);

最坏的情况就是元素都是逆序的,如{6,5,4,3,2,1},所以都需要比较,移动次数达到O(n^2).

稳定性:稳定

插入排序,初始数据越接近有序,时间效率越高

2.希尔排序

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。

希尔对记录的分组,不是简单地“逐段分割”,而是将相隔某个“增量”的记录分成一组。

在严薇敏的《数据结构》里面是这样说的:

上面的话可能有点难理解,下面我们通过画图来了解一下希尔排序的本质。

希尔排序跟直接插入排序有点相似,可以说是直接插入排序的升级版。不同在于,希尔排序的比较方式变成了跳跃式的。比如说下面这组数据的第一次排序。

最终排序完成了。

我们来看一下希尔排序的代码:

    public static void shell(int[] array,int gap) {
        for (int i = gap; i < array.length; i++ ) {
            int tmp = array[i];
            int j = i-gap;
            for (; j >= 0 ; j -= gap) {
                if(array[j] > tmp) {
                    array[j+gap] = array[j];
                }else {
                    break;
                }
            }
            array[j+gap] = tmp;
        }
    }

//按照5、3、1分组
    public static void shellSort1(int[] array) {
        int[] drr = {5,3,1};
        for (int i = 0; i < drr.length; i++) {
            shell(array,drr[i]);
        }
    }

是不是跟直接插入排序很像?所以我们才说,希尔排序是直接插入排序的升级版。它不是随便分组后各自排序,而是将相隔某个增量gap的记录组成一个子序列,实现跳跃式移动,使得排序的效率提高了。

所以,选取“增量”是非常关键的一步,值得一提的是,选取什么样的“增量”,目前为止尚没有一个没完美的增量序列。

复杂度分析:

  • 时间复杂度[和增量有关系的]:O(n^1.3 - n^1.5)。
  • 空间复杂度:O(1)

稳定性:不稳定的。

3.简单选择排序

简单选择排序:通过n-i次关键字间的比较,从n-i+1个记录中选出关键字最小的记录,并和第 i(1 ≤ i ≤n) 个记录交换

    public static void selectSort1(int[] array) {
        for (int i = 0; i < array.length; i++) {
            for (int j = i+1; j < array.length; j++) {
                //1 2 3 4 5 6
                if(array[j] < array[i]) {
                    swap(array,i,j);
                }
            }
        }
    }
    public static void swap(int[] array,int i,int j) {
        int tmp = array[i];
        array[i] = array[j];
        array[j] = tmp;

有时候,我们可能不需要循环那么多次,循环一两次就有序了,如果在有序的序列中继续循环,则会造成时间的浪费。为避免这种情况,所以我们可以对代码进行稍稍改进:

    public static void selectSort(int[] array) {
        for (int i = 0; i < array.length; i++) {
            int minIndex = i;
            for (int j = i+1; j < array.length; j++) {
                //找到最小值下标
                if(array[j] < array[minIndex]) {
                    minIndex = j;
                }
            }
            swap(array,i,minIndex);
        }
    }

复杂度分析:

  • 时间复杂度:O(n^2)
  • 空间复杂度:同接下介绍的冒泡排序一样,只有在两个记录交换时需要一个辅助空间,所以空间复杂度为O(1).

稳定性:稳定

4.堆排序

堆排序的基本原理也是选择排序,只是不在使用遍历的方式查找无序区间的最大的数,而是通过堆来选择无序区间的最大的数。

我上一篇文章有详细介绍,这里就不再说了,大家感兴趣可以去了解一下。 Java数据结构之优先级队列(堆)图文详解

这里也给一下代码:

    public static void heapSort(int[] array) {
        //1、建堆  O(N)
        createHeap(array);
        int end = array.length-1;
        //2、交换然后调整 O(N * log N)
        while (end > 0) {
            swap(array,0,end);
            shiftDown(array,0,end);
            end--;
        }
    }

    public static void createHeap(int[] array) {
        for (int parent = (array.length-1-1)/2; parent >= 0 ; parent--) {
            shiftDown(array,parent,array.length);
        }
    }

    public static void shiftDown(int[] array,int parent,int len) {
        int child = 2*parent+1;//左孩子下标
        while (child < len) {
            if(child+1 < len && array[child] < array[child+1]) {
                child++;
            }
            //child下标 就是左右孩子最大值的下标
            if(array[child] > array[parent]) {
                swap(array,child,parent);
                parent = child;
                child = 2*parent+1;
            }else {
                break;
            }
        }
    }

复杂度分析:

  • 时间复杂度:O(n * log2(n))——2指的是以2为底
  • 空间复杂度:O(1)

稳定性:不稳定

【注意】

  • 堆排序只能用于顺序结构,不能用于链式结构
  • 由于建初堆的时候所需比较的次数较多,因此记录次数较少时不宜采用。

5.冒泡排序

冒泡排序是一种交换排序,它的基本思想是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。

代码:

    public static  void bubbleSort(int[] array) {
        for (int i = 0; i < array.length-1; i++) {
            for (int j = 0; j < array.length-1; j++) {
                if(array[j] > array[j+1]) {
                    swap(array,j+1,j);
                }
            }
        }
    }
 public static void swap(int[] array,int i,int j) {
        int tmp = array[i];
        array[i] = array[j];
        array[j] = tmp;

复杂度分析:

  • 时间复杂度:O(N^2)
  • 空间复杂度:O(1)

稳定性:稳定。

6.快速排序

6.1.递归快速排序

快速排序是冒泡排序的升级版,它们都属于交换排序类,即它也是通过不断比较和移动交换来实现排序,不同的是,快排的实现增大的了记录的比较和移动的距离。

快排将关键字较大的数据从前面直接移到后面,关键字较小的记录从后面直接移到前面,从而减少了总的比较次数和移动交换次数。

快排的基本思想:

通过一趟排序将待排序的数据分割成独立的两部分,其中一部分比另一部小,然后再分别对这两部分记录并再次进行排序,以达到整个序列有序。

我们翻译翻译一下上面的那段话:

  • 首先,你得有一个中间数,比它小的放一边,比它大的放一边。这个数,我们称为基准值。
  • 采用分治思想,对左右两个小区间按照同样的方式处理,直到小区间的长度 == 1,代表已经有序,或者小区间的长度 == 0,代表没有数据。

可能大家看到这里也还是有点迷惑,我们直接上代码。

    public static void quickSort(int[] array) {
        quick(array,0,array.length-1);
    }

    public static void quick(int[] array,int left,int right) {
        if(left >= right) {
            return;
        }
        int pivot = partition(array,left,right);//基准
        quick(array,left,pivot-1);
        quick(array,pivot+1,right);
    }

上面的代码是不是有点像二叉树的遍历?

这二者确实有相似之处,我们后面再讲。

上面还有一个partition函数,这个函数是我们快速排序最关键的地方。

 /**
     * 找基准
     * @param array 待排序数组对象
     * @param start左边界
     * @param end右边界
     * @return 基准值下标
     */
    private static int partition(int[] array,int start,int end) {
        int tmp = array[start];
        while (start < end) {
            while (start < end && array[end] >= tmp) {
                end--;
            }
            //end下标就遇到了 < tmp的值
            array[start] = array[end];
            while (start < end && array[start] <= tmp) {
                start++;
            }
            //start下标就遇到了 > tmp的值
            array[end] = array[start];
        }
        array[start] = tmp;
        return start;
    }

我们下面通过图解模拟一下函数的运行过程:

可以看到,当第一轮走完之后,数据由基准值分成了两部分。

之后,我们再次对左右两部分完成同样的操作,如下:

一直递归下来,跟二叉树的遍历类似。

复杂度分析:

时间复杂度:

  • 最好情况下:O(nlogn)
  • 最坏情况下:O(n^2).

空间复杂度:O(logn)

稳定性:不稳定

  • 快排优化

不知大家看上面的图解的时候有没有一点困惑,就是我们这基准选得不好,导致第一趟递归下来的效果不好,变成了如下图:

如果我们有一种办法,先找到相对居中的那个数字,那么整个排序的时间复杂度是不是大大减小了。

于是,有人提出了随机选取一个值来作为基准,称为随机选取法。

这种做法,得看运气,因为假如选的好,刚刚选取中间值,那么,性能大大提高;如果随机得不好,比如随机到最小值或者最大值,那么性能则变成最差了。

所以有人提出一个新的方法,三数取中:

取三个关键字先进行排序,将中间数作为基准,一般取左端,右端和中间三个数。

如果运用三数取中这种方法的话,第一次比较的结果如下:

可以看到,11基本上与中间的数字相差不远了,性能大大提高。

所以,这里我们再写一个找基准的代码:

/**
     * 找基准 三数取中法
     * @param array 待排序数组对象
     * @param left 左边界
     * @param right 右边界
     * @return 基准值下标
     */
    private static int findMidValIndex(int[] array,int start,int end) {
        int mid = start + ((end-start) >>> 1);
        if(array[start] < array[end]) {
            if(array[mid] < array[start]) {
                return start;
            }else if(array[mid] > array[end]) {
                return end;
            }else {
                return mid;
            }
        }else {
            if(array[mid] > array[start]) {
                return start;
            }else if(array[mid] < array[end]) {
                return end;
            }else {
                return mid;
            }
        }
    }

前面quick函数改动一下,如下:

    public static void quick(int[] array,int left,int right) {
        if(left >= right) {
            return;
        }

        //采用三数取中法找基准值
        int midValIndex = findMidValIndex(array,left,right);
        swap(array,midValIndex,left);

        int pivot = partition(array,left,right);//基准
        quick(array,left,pivot-1);
        quick(array,pivot+1,right);
    }

其实,优化到这里已经很棒了 。但是,我们还能优化。

这里先插播一个知识点:

直接插入是简单排序中性能最好的。 所以如果要我们要排序的数组非常小,直接插入排序会更好。 原因在于,快速排序用到了递归操作,在大量的数据排序时,这点性能影响相对它的整体算法优势而言是可以忽略的。但是如果数组只有不多的数据需要排序,就有点大材小用了。

因此,我们在这里的优化是:

增加一个判断,当 right-left+1 不大于某个常数时,就用直接插入排序,这个常数是具体情况而定。这样我们就能保证最大化地利用两种排序的优势来完成排序工作了。

/**
     * 优化,加入插入排序
     * @param array 待排序数组对象
     * @param left 左边界
     * @param right 右边界
     * @return 基准值下标
     */
    public static void quick(int[] array,int left,int right) {
        if(left >= right) {
            return;
        }
        //加一个判断,如果区间内的数据,在排序的过程当中,小于某个范围了,可以使用直接插入排序
        if(right-left+1 <= 1400) {
            //使用直接插入排序
            insertSort2(array,left,right);
            return;
        }

        //1、找基准之前,我们找到中间大小的值-使用三数取中法
        int midValIndex = findMidValIndex(array,left,right);
        swap(array,midValIndex,left);

        int pivot = partition(array,left,right);//基准
        quick(array,left,pivot-1);
        quick(array,pivot+1,right);
    }

//插入排序
    public static void insertSort(int[] array,int start,int end) {
        for (int i = 1; i <= end; i++) {
            int tmp = array[i];
            int j = i-1;
            for (; j >= start ; j--) {
                if(array[j] > tmp) {
                    array[j+1] = array[j];
                }else {
                    break;
                }
            }
            array[j+1] = tmp;
        }
    }

6.2.非递归方式实现

我们都知道,递归对性能是有一定影响的。所以我们也可以采用非递归的方式来实现快速排序

/**
     * 快速排序非递归实现
     * @param array 待排序数组
     */
    public static void quickSort(int[] array) {
        Stack<Integer> stack = new Stack<>();
        int left = 0;
        int right = array.length-1;
        int pivot = partition(array,left,right);
        if(pivot > left+1) {
            stack.push(left);
            stack.push(pivot-1);
        }
        if(pivot < right-1) {
            stack.push(pivot+1);
            stack.push(right);
        }

        while (!stack.isEmpty()) {
           right = stack.pop();
           left = stack.pop();
           pivot = partition(array,left,right);

            if(pivot > left+1) {
                //左边有2个元素
                stack.push(left);
                stack.push(pivot-1);
            }
            if(pivot < right-1) {
                //右边有2个元素
                stack.push(pivot+1);
                stack.push(right);
            }
        }
    }

非递归复杂度分析:

时间复杂度:

  • 最坏情况下: O(n^2)
  • 平均情况下:O(nlogn)

空间复杂度:

  • 最坏情况下:O(n)
  • 平均情况下:O(logn)

稳定性:不稳定

7.归并排序

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

7.1.递归归并排序

直接上代码:

//调用了mergeSortInternal函数
    public static void mergeSort1(int[] array) {
        mergeSortInternal(array,0,array.length-1);
    }

    private static void mergeSortInternal(int[] array,int low,int high) {
        if(low>=high) {
            return;
        }

        int mid = low + ((high-low) >>> 1);//>>>无符号右移1位。就是除以2,找中间值
        //左边递归
        mergeSortInternal(array,low,mid);
        //右边递归
        mergeSortInternal(array,mid+1,high);
        //合并两边数组
        merge(array,low,mid,high);
    }

mergeSortInternal函数的图解:

其实就是对半分开数组

这里这个merge函数是归并排序里面的关键,无论是采用递归还是非递归都必须采用到这部分的函数。

而其本质,其实就是合并两个数组,并使其有序起来。

merge函数的代码:

    private static void merge(int[] array,int low,int mid,int high) {
        int[] tmp = new int[high-low+1];
        int k = 0;//

        int s1 = low;
        int e1 = mid;
        int s2 = mid+1;
        int e2 =  high;
        while (s1 <= e1 && s2 <= e2) {
            if(array[s1] <= array[s2]) {
                tmp[k++] = array[s1++];
            }else {
                tmp[k++] = array[s2++];
            }
        }
        while (s1 <= e1) {
            tmp[k++] = array[s1++];
        }
        while (s2 <= e2) {
            tmp[k++] = array[s2++];
        }
        //拷贝tmp数组的元素 放入原来的数组array当中
        for (int i = 0; i < k; i++) {
            array[i+low] = tmp[i];
        }
    }

7.2.非递归归并排序

归并排序除了用递归的方式来实现,也可以用非递归的方式来实现。

    public static void mergeSort(int[] array) {
        int nums = 1;//每组的数据个数
        while (nums < array.length) {
            //数组每次都要进行遍历,确定要归并的区间
            for (int i = 0; i < array.length; i += nums*2) {
                int left = i;
                int mid = left+nums-1;
                //防止越界
                if(mid >= array.length) {
                    mid = array.length-1;
                }
                int right = mid+nums;
                //防止越界
                if(right >= array.length) {
                    right = array.length-1;
                }
                //小标确定之后,进行合并
                merge(array,left,mid,right);
            }
            nums *= 2;数组合并后,以1-2-4-8-16-进行循环
        }
    }

图解如下:

总结

这次常见排序的文章,来来回回写了两天左右,在写的过程,也是学习的过程,特别是里面画图的时候,得理清楚整个排序的思想,才能很好的作出整个图解出来。各位看客老爷们,希望看到能给个三连,感谢!

到此这篇关于Java数据结构常见几大排序梳理的文章就介绍到这了,更多相关Java 排序内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java深入了解数据结构中常见的排序算法

    目录 一,概念 1,排序 2,稳定性 二,排序详解 1,插入排序 ①直接插入排序 2,选择排序 ①直接选择排序 ②堆排序 3,交换排序 ①冒泡排序 ②快速排序 4,归并排序 一,概念 1,排序 排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作. 平时的上下文中,如果提到排序,通常指的是排升序(非降序). 通常意义上的排序,都是指的原地排序(in place sort). 2,稳定性 两个相等的数据,如果经过排序后,排序算法能保证其相对位置不发生变化,则我们称该算

  • Java数据结构和算法之冒泡,选择和插入排序算法

    目录 1.冒泡排序 2.选择排序 3.插入排序 4.总结 1.冒泡排序 这个名词的由来很好理解,一般河水中的冒泡,水底刚冒出来的时候是比较小的,随着慢慢向水面浮起会逐渐增大,这物理规律我不作过多解释,大家只需要了解即可. 冒泡算法的运作规律如下: ①.比较相邻的元素.如果第一个比第二个大,就交换他们两个. ②.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对.这步做完后,最后的元素会是最大的数(也就是第一波冒泡完成). ③.针对所有的元素重复以上的步骤,除了最后一个. ④.持续每次对越

  • Java数据结构之二叉排序树的实现

    目录 1 二叉排序树的概述 2 二叉排序树的构建 2.1 类架构 2.2 查找的方法 2.3 插入的方法 2.4 查找最大值和最小值 2.5 删除的方法 3 二叉排序树的总结 1 二叉排序树的概述 本文没有介绍一些基础知识.对于常见查找算法,比如顺序查找.二分查找.插入查找.斐波那契查找还不清楚的,可以看这篇文章:常见查找算法详解以及Java代码的实现. 假设查找的数据集是普通的顺序存储,那么插入操作就是将记录放在表的末端,给表记录数加一即可,删除操作可以是删除后,后面的记录向前移,也可以是要删

  • Java最简洁数据结构之冒泡排序快速理解

    目录 一.什么是冒泡排序 二.图解冒泡排序 三.代码实现 四.代码的优化 1.整体的思路 2.代码示例 一.什么是冒泡排序 冒泡排序的英文是bubble sort,它是一种基础的交换排序.说到冒泡是不是就想起了快乐肥宅水呢?汽水中有许多小小的水泡哗啦哗啦的浮到上面来.这是因为组成小气泡的二氧化碳比水轻,所以小气泡可以一点一点地向上浮动. 而冒泡排序之所以叫冒泡排序,正是因为这种排序算法的每一个元素都可以像小气泡一样,根据自身的大小,一点一点的向着数组的一侧移动. 二.图解冒泡排序 我们先看一个例

  • java 数据结构与算法 (快速排序法)

    快速排序法: 顾名思议,快速排序法是实践中的一种快速的排序算法,在c++或对java基本类型的排序中特别有用.它的平均运行时间是0(N log N).该算法之所以特别快,主要是由于非常精练和高度优化的内部循环.快速排序是对冒泡法的一种改进.通过一趟排序将要排序的的数据分割成独立的两部分,其中一部分的所有数据都比另一部分所有的数据要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列. 示意图: 这里 定义最左边元素 为left 最右边元素为ri

  • Java 数据结构与算法系列精讲之排序算法

    概述 从今天开始, 小白我将带大家开启 Java 数据结构 & 算法的新篇章. 冒泡排序 冒泡排序 (Bubble Sort) 是一种简单的排序算法. 它重复地遍历要排序的数列, 一次比较两个元素, 如果他们的顺序错误就把他们交换过来. 遍历数列的工作是重复地进行直到没有再需要交换, 也就是说该数列已经排序完成. 这个算法的名字由来是因为越小的元素会经由交换慢慢 "浮" 到数列的顶端. 冒泡排序流程: 通过比较相邻的元素, 判断两个元素位置是否需要互换 进行 n-1 次比较,

  • 带你了解Java数据结构和算法之高级排序

    目录 1.希尔排序 ①.直接插入排序 ②.希尔排序图解 ③.排序间隔选取 ④.knuth间隔序列的希尔排序算法实现 ⑤.间隔为2h的希尔排序 2.快速排序 ①.快速排序的基本思路 ②.快速排序的算法实现 ③.快速排序图示 ④.快速排序完整代码 ⑤.优化分析 总结 1.希尔排序 希尔排序是基于直接插入排序的,它在直接插入排序中增加了一个新特性,大大的提高了插入排序的执行效率.所以在讲解希尔排序之前,我们先回顾一下直接插入排序. ①.直接插入排序 直接插入排序基本思想是每一步将一个待排序的记录,插入

  •  Java数据结构的十大排序

    目录 1.直接插入排序 1.1 动图演示 1.2 插入排序的思路 1.3 代码实现 1.4 性能分析 2.希尔排序 2.1 原理 2.2 动图演示 2.3 代码实现 2.4 性能分析 3.直接选择排序 3.1 动图演示 3.2 代码实现 3.3 性能分析 4.堆排序 4.1 动图演示 4.2 代码实现 4.3 性能分析 5.冒泡排序 5.1 动图演示 5.2 代码实现 5.3 性能分析 6.快速排序 6.1 原理 6.2 动图演示 6.3 实现方法 6.3.1 Hoare法 6.3.2 挖坑法

  • Java数据结构常见几大排序梳理

    目录 一.排序的概念和分类 1.排序的基本概念 2.排序的稳定性 二.常见排序 1.直接插入排序 2.希尔排序 3.简单选择排序 4.堆排序 5.冒泡排序 6.快速排序 6.1.递归快速排序 6.2.非递归方式实现 7.归并排序 7.1.递归归并排序 7.2.非递归归并排序 总结 一.排序的概念和分类 1.排序的基本概念 排序是将一批无序的记录(数据)重新排列成按关键字有序的记录序列的过程. 排序分为内部排序和外部排序 若整个排序过程不需要访问外存便能完成,则称此类排序问题为内部排序. 反之,若

  • Java实现常见的排序算法的示例代码

    目录 一.优化后的冒泡排序 二.选择排序 三.插入排序 四.希尔排序 五.快速排序 六.随机化快速排序 七.归并排序 八.可处理负数的基数排序 一.优化后的冒泡排序 package com.yzh.sort; /* 冒泡排序 */ @SuppressWarnings({"all"}) public class BubbleSort { public static void BubbleSort(int[]a){ for (int i = 0; i <a.length-1 ; i+

  • java数据结构之希尔排序

    希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本.希尔排序是非稳定排序算法. 希尔排序是基于插入排序的以下两点性质而提出改进方法的: 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率:         但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位. 实现: 先取一个正整数d1 < n, 把所有相隔d1的记录放一组,每个组内进行直接插入排序:然后d2 < d1,重复上述分组和排序操作:直至di = 1,即所有记录放进一个组中排序为止. 简

  • Java数据结构之常见排序算法(上)

    目录 认识排序 常见排序的分类 直接插入排序 希尔排序(缩小增量排序) 选择排序 堆排序 认识排序 在学校中,如果我们要参加运动会,或者军训的时候,会按照身高从矮到高进行站队,比如上课老师手上拿的考勤表,通常是按照学号从低到高进行排序的.再比如编程语言排行榜,也是在排序. 生活中有相当多的排序场景,由此可知,排序还是很重要的, 本章就会介绍常见的一些排序算法. 所谓排序呢,就拿我们上面的举例来说,会按照某个或某些关键字的大小,递增或者递减排列起来的操作,这就是排序,这里面也涉及到排序的稳定性,举

  • java数据结构与算法之桶排序实现方法详解

    本文实例讲述了java数据结构与算法之桶排序实现方法.分享给大家供大家参考,具体如下: 基本思想: 假定输入是由一个随机过程产生的[0, M)区间上均匀分布的实数.将区间[0, M)划分为n个大小相等的子区间(桶),将n个输入元素分配到这些桶中,对桶中元素进行排序,然后依次连接桶输入0 ≤A[1..n] <M辅助数组B[0..n-1]是一指针数组,指向桶(链表).将n个记录分布到各个桶中去.如果有多于一个记录分到同一个桶中,需要进行桶内排序.最后依次把各个桶中的记录列出来记得到有序序列. [桶-

  • Java数组常见应用详解【创建、遍历、排序、查找】

    本文实例讲述了Java数组常见应用.分享给大家供大家参考,具体如下: 双重for循环 外循环控制行,内循环控制列. //乘法表 for(int i = 1; i <= 9; i++) { for(int j = 1; j <= i ;j++) { System.out.print(j+"*"+i+"="+(i*j)+"\t"); } System.out.println(); } DecimalFormat #:一个数字 0:一个数字

  • 浅谈Java常见的排序算法

    目录 一.直接插入排序 二. 希尔排序 三.冒泡排序 四.快速排序 五.选择排序(Selection Sort) 六.堆排序 七.归并排序 一.直接插入排序 基本思想: 将一个记录插入到已排序的有序表中,使插入后的表仍然有序 对初始关键字{49 38 65 97 76 13 27 49}进行直接插入排序 package Sort; //插入排序 public class InsertSort { public static void main(String[] args) { int [] ar

  • Java数据结构之基于比较的排序算法基本原理及具体实现

    目录 1. 七大基于比较的排序-总览 1.1常见基于比较的排序分类 1.2时间复杂度,空间复杂度以及稳定性. 2.直接插入排序 2.1 直接插入排序的基本思想 2.2 直接插入排序动画演示 2.3 代码示例 2.4 时间复杂度,空间复杂度以及稳定性 3. 希尔排序 3.1 算法思想 3.2 图片演示 3.3 代码示例 3.4 时间复杂度,空间复杂度以及稳定性 4.选择排序 4.1 算法思想 4.2 动画演示 4.3 代码示例 4.4 时间复杂度,空间复杂度以及稳定性 5.堆排序 5.1 算法思想

  • Java数据结构之插入排序与希尔排序

    目录 一.正文 1.排序的概念及其运用 1.1排序的概念 1.2排序运用 1.3常见的排序算法 2.插入排序算法的实现 2.1插入排序 二.测试代码 三.结语 一.正文 1.排序的概念及其运用 1.1排序的概念 排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作. 稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次 序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[

随机推荐