Java集合和数据结构排序实例详解

目录
  • 概念
  • 插入排序
    • 直接插入排序
      • 代码实现
      • 性能分析
    • 希尔排序
      • 代码实现
      • 性能分析
  • 选择排序
    • 直接选择排序
      • 代码实现
      • 性能分析
    • 堆排序
      • 代码实现
      • 性能分析
  • 交换排序
    • 冒泡排序
      • 代码实现
      • 性能分析
    • 快速排序
      • 代码实现
      • 性能分析
    • 非递归实现快速排序
      • 代码实现
      • 性能分析
  • 归并排序
    • 归并排序
      • 代码实现
      • 性能分析
    • 非递归实现归并排序
      • 代码实现
      • 性能分析
  • 海量数据的排序问题
  • 总结

概念

排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。

平时的上下文中,如果提到排序,通常指的是排升序(非降序)。

通常意义上的排序,都是指的原地排序(in place sort)。

稳定性: 两个相等的数据,如果经过排序后,排序算法能保证其相对位置不发生变化,则我们称该算法是具备稳定性的排序算法。

插入排序

直接插入排序

整个区间被分为

  • 有序区间
  • 无序区间

每次选择无序区间的第一个元素,在有序区间内选择合适的位置插入

代码实现

逻辑代码:

public class InsertSort {
    public static void insertSort(int[] array) {
        for (int i = 1; i < array.length; i++) {
            int temp = array[i];
            int j = i-1;
            for (; j >= 0; j--) {
                if (array[j] > temp) {
                    array[j+1] = array[j];
                }else {
                    break;
                }
            }
            array[j+1] = temp;
        }
    }
}

调试代码:

public class TestDemo {
    public static void main(String[] args) {
        int[] array = {10,3,2,7,19,78,65,127};
        System.out.println("排序前:" + Arrays.toString(array));
        InsertSort.insertSort(array);
        System.out.println("排序后:" + Arrays.toString(array));
    }
}

该代码的执行结果为:

可见,实现了对原数组的升序排序。

性能分析

时间复杂度:
最好情况:O(n)【数据有序】
平均情况:O(n2)
最坏情况:O(n2)【数据逆序】

空间复杂度:O(1)

稳定性:稳定

对于直接插入排序:越有序越快。另外,直接插入排序会用在一些排序的优化上。

希尔排序

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

希尔排序是对直接插入排序的优化。
当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。

代码实现

逻辑代码:

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

    public static void shellSort(int[] array) {
        int[] drr = {5,3,1};//增量数组-->没有明确的规定,但保证为素数的增量序列
        for (int i = 0; i < drr.length; i++) {
            shell(array,drr[i]);
        }
    }
}

测试代码:

public class TestDemo {
    public static void main(String[] args) {
        int[] array = {10,3,2,7,19,78,65,127};
        System.out.println("排序前:" + Arrays.toString(array));
        ShellSort.shellSort(array);
        System.out.println("排序后:" + Arrays.toString(array));
    }
}

该代码的执行结果为:

可见,实现了对原数组的升序排序。

性能分析

时间复杂度:
最好情况:O(n)【数据有序】
平均情况:O(n1.3)
最坏情况: O(n2) 【比较难构造】

空间复杂度:O(1)

稳定性:不稳定

选择排序

直接选择排序

每一次从无序区间选出最大(或最小)的一个元素,存放在无序区间的最后(或最前),直到全部待排序的数据元素排完 。

代码实现

逻辑代码:

public class SelectSort {
    public static void selectSort(int[] array) {
        for (int i = 0; i < array.length-1; i++) {
            for (int j = i+1; j < array.length; j++) {
                if (array[i] > array[j]) {
                    int temp = array[j];
                    array[j] = array[i];
                    array[i] = temp;
                }
            }
        }
    }
}

测试代码:

public class TestDemo {
    public static void main(String[] args) {
        int[] array = {10,3,2,7,19,78,65,127};
        System.out.println("排序前:" + Arrays.toString(array));
        SelectSort.selectSort(array);
        System.out.println("排序后:" + Arrays.toString(array));
    }
}

该代码的执行结果为:

可见,实现了对原数组的升序排序。

性能分析

时间复杂度 : 不管是最好情况还是最坏情况都是O(n2) 【数据不敏感】

空间复杂度: O(1)

稳定性:不稳定

堆排序

基本原理也是选择排序,只是不在使用遍历的方式查找无序区间的最大的数,而是通过堆来选择无序区间的最大的数。
注意:排升序要建大堆;排降序要建小堆。

代码实现

逻辑代码:

public class HeapSort {
    public static void heapSort(int[] array) {
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1-o2;
            }
        });
        for (int i = 0; i < array.length; i++) {
            priorityQueue.add(array[i]);
        }
        for (int i = 0; i < array.length; i++) {
            array[i] = priorityQueue.poll();
        }
    }
}

测试代码:

public class TestDemo {
    public static void main(String[] args) {
        int[] array = {10,3,2,7,19,78,65,127};
        System.out.println("排序前:" + Arrays.toString(array));
        HeapSort.heapSort(array);
        System.out.println("排序后:" + Arrays.toString(array));
    }
}

该代码的执行结果为:

可见,实现了对原数组的升序排序。

性能分析

时间复杂度:不管是最好的情况还是最坏的情况都是O(n * log(n)) 。

空间复杂度:O(1)。

稳定性:不稳定

交换排序

冒泡排序

在无序区间,通过相邻数的比较,将最大的数冒泡到无序区间的最后,持续这个过程,直到数组整体有序。

代码实现

逻辑代码:

public class BubbleBort {
    public static void bubbleBort(int[] array) {
        for (int i = 0; i < array.length-1; i++) {
            for (int j = 0; j < array.length-i-1; j++) {
                if (array[j] > array[j+1]) {
                    int temp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = temp;
                }
            }
        }
    }
}

测试代码:

public class TestDemo {
    public static void main(String[] args) {
        int[] array = {10,3,2,7,19,78,65,127};
        System.out.println("排序前:" + Arrays.toString(array));
        BubbleBort.bubbleBort(array);
        System.out.println("排序后:" + Arrays.toString(array));
    }
}

该代码的执行结果为:

可见,实现了对原数组的升序排序。

性能分析

时间复杂度:
最好情况:O(n)【数据有序】
平均情况:O(n2)
最坏情况: O(n2) 【数据逆序】

空间复杂度:O(1)。

稳定性:稳定

快速排序

  1. 从待排序区间选择一个数,作为基准值(pivot);
  2. Partition: 遍历整个待排序区间,将比基准值小的(可以包含相等的)放到基准值的左边,将比基准值大的(可以包含相等的)放到基准值的右边;
  3. 采用分治思想,对左右两个小区间按照同样的方式处理,直到小区间的长度 = 1,代表已经有序,或者小区间的长度 = 0,代表没有数据。

代码实现

逻辑代码:

public class QuickSort {
    public static void quick(int[] array,int low,int high) {
        if (low < high) {
            int piv = piovt(array,low,high);//找基准
            quick(array,low,piv-1);
            quick(array,piv+1,high);
        }
    }

    private static int piovt(int[] array,int start,int end) {
        int temp = array[start];
        while (start < end) {
            while (start < end && array[end] >= temp) {
                end--;
            }
            array[start] = array[end];

            while (start < end && array[start] < temp) {
                start++;
            }
            array[end] = array[start];
        }
        array[start] = temp;
        return start;
    }

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

测试代码:

public class TestDemo {
    public static void main(String[] args) {
        int[] array = {10,3,2,7,19,78,65,127};
        System.out.println("排序前:" + Arrays.toString(array));
        QuickSort.quickSort(array);
        System.out.println("排序后:" + Arrays.toString(array));
    }
}

该代码的执行结果为:

可见,实现了对原数组的升序排序。

性能分析

时间复杂度:
最好情况:O(n * log(n))
平均情况:O(n * log(n))
最坏情况: O(n2)

空间复杂度:
最好情况:O(log(n))
平均情况:O(log(n))
最坏情况:O(n)

稳定性:不稳定

非递归实现快速排序

代码实现

逻辑代码:

/**
 * 非递归实现快速排序
 */
public class QuickSortNor {
    public static void quickSortNor(int[] array) {
        int low = 0;
        int high = array.length - 1;
        int piv = piovt(array, low, high);
        Stack<Integer> stack = new Stack<>();
        if (piv > low + 1) {
            stack.push(low);
            stack.push(piv - 1);
        }
        if (piv < high - 1) {
            stack.push(piv + 1);
            stack.push(high);
        }
        while (!stack.isEmpty()) {
            high = stack.pop();
            low = stack.pop();
            piv = piovt(array, low, high);
            if (piv > low + 1) {
                stack.push(low);
                stack.push(piv - 1);
            }
            if (piv < high - 1) {
                stack.push(piv + 1);
                stack.push(high);
            }
        }
    }

    private static int piovt(int[] array, int start, int end) {
        int temp = array[start];
        while (start < end) {
            while (start < end && array[end] >= temp) {
                end--;
            }
            array[start] = array[end];
            while (start < end && array[start] < temp) {
                start++;
            }
            array[end] = array[start];
        }
        array[start] = temp;
        return start;
    }
}

测试代码:

public class TestDemo {
    public static void main(String[] args) {
        int[] array = {10,3,2,7,19,78,65,127};
        System.out.println("排序前:" + Arrays.toString(array));
        QuickSortNor.quickSortNor(array);
        System.out.println("排序后:" + Arrays.toString(array));
    }
}

该代码的执行结果为:

可见,实现了对原数组的升序排序。

性能分析

时间复杂度: O(n * log(n))

空间复杂度:
最好情况:O(log(n))
最坏情况:O(n)

稳定性:不稳定

归并排序

归并排序

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

代码实现

逻辑代码:

public class MergeSort {
    public static void merge(int[] array, int start, int mid, int end) {
        int s1 = start;
        int s2 = mid + 1;
        int[] temp = new int[end - start + 1];
        int k = 0;
        while (s1 <= mid && s2 <= end) {
            if (array[s1] <= array[s2]) {
                temp[k++] = array[s1++];
            } else {
                temp[k++] = array[s2++];
            }
        }
        while (s1 <= mid) {
            temp[k++] = array[s1++];
        }
        while (s2 <= end) {
            temp[k++] = array[s2++];
        }
        for (int i = 0; i < temp.length; i++) {
            array[i + start] = temp[i];
        }
    }

    public static void mergeSortInternal(int[] array, int low, int high) {
        if (low >= high) return;
        //先分解
        int mid = (low + high) / 2;
        mergeSortInternal(array, low, mid);
        mergeSortInternal(array, mid + 1, high);
        //再合并
        merge(array, low, mid, high);
    }

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

测试代码:

public class TestDemo {
    public static void main(String[] args) {
        int[] array = {10,3,2,7,19,78,65,127};
        System.out.println("排序前:" + Arrays.toString(array));
        MergeSort.mergeSort(array);
        System.out.println("排序后:" + Arrays.toString(array));
    }
}

该代码的执行结果为:

可见,实现了对原数组的升序排序。

性能分析

时间复杂度: O(n * log(n))

空间复杂度:O(n)

稳定性:稳定

非递归实现归并排序

代码实现

逻辑代码:

/**
 * 非递归实现归并排序
 */
public class MergeSortNor {
    public static void merge(int[] array, int gap) {
        int s1 = 0;
        int e1 = s1 + gap - 1;
        int s2 = e1 + 1;
        int e2 = s2 + gap - 1 < array.length ? s2 + gap - 1 : array.length - 1;
        int[] temp = new int[array.length];
        int k = 0;
        while (s2 < array.length) {
            while (s1 <= e1 && s2 <= e2) {
                if (array[s1] <= array[s2]) {
                    temp[k++] = array[s1++];
                } else {
                    temp[k++] = array[s2++];
                }
            }
            while (s1 <= e1) {
                temp[k++] = array[s1++];
            }
            while (s2 <= e2) {
                temp[k++] = array[s2++];
            }
            s1 = e2+1;
            e1 = s1+gap-1;
            s2 = e1+1;
            e2 = s2 + gap - 1 < array.length ? s2 + gap - 1 : array.length - 1;
        }
        while (s1 < array.length) {
            temp[k++] = array[s1++];
        }

        for (int i = 0; i < temp.length; i++) {
            array[i] = temp[i];
        }
    }

    public static void mergeSortNor(int[] array) {
        for (int i = 1; i < array.length; i *= 2) {
            merge(array, i);
        }
    }
}

测试代码:

public class TestDemo {
    public static void main(String[] args) {
        int[] array = {10,3,2,7,19,78,65,127};
        System.out.println("排序前:" + Arrays.toString(array));
        MergeSortNor.mergeSortNor(array);
        System.out.println("排序后:" + Arrays.toString(array));
    }
}

该代码的执行结果为:

可见,实现了对原数组的升序排序。

性能分析

时间复杂度: O(n * log(n))

空间复杂度:O(n)

稳定性:稳定

海量数据的排序问题

外部排序:排序过程需要在磁盘等外部存储进行的排序

前提:内存只有 1G,需要排序的数据有 100G

因为内存中因为无法把所有数据全部放下,所以需要外部排序,而归并排序是最常用的外部排序。

  1. 先把文件切分成 200 份,每个 512 M
  2. 分别对 512 M 排序,因为内存已经可以放的下,所以任意排序方式都可以
  3. 进行 200 路归并,同时对 200 份有序文件做归并过程,最终结果就有序了

排序总结


总结

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

(0)

相关推荐

  • Java中集合和数组的排序方式小结

    根据约定,在使用java编程的时候应尽可能的使用现有的类库,当然你也可以自己编写一个排序的方法,或者框架,但是有几个人能写得比JDK里的还要好呢?使用现有的类的另一个好处是代码易于阅读和维护,这篇文章主要讲的是如何使用现有的类库对数组和各种Collection容器进行排序,(文章中的一 部分例子来自<Java Developers Almanac 1.4>) 首先要知道两个类:java.util.Arrays和java.util.Collections(注意和Collection的区 别)Co

  • Java sort集合排序的两种方式解析

    这篇文章主要介绍了Java sort集合排序的两种方式解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Comparable和Comparator public static <T> void sort(List<T> list); 将集合中的数据按照默认规则进行排序 (我们在自己的类里面实现Comparabl接口方法compareTo) public static <T> void sort(List<T&g

  • java如何对map进行排序详解(map集合的使用)

    今天做统计时需要对X轴的地区按照地区代码(areaCode)进行排序,由于在构建XMLData使用的map来进行数据统计的,所以在统计过程中就需要对map进行排序. 一.简单介绍Map 在讲解Map排序之前,我们先来稍微了解下map.map是键值对的集合接口,它的实现类主要包括:HashMap,TreeMap,Hashtable以及LinkedHashMap等.其中这四者的区别如下(简单介绍): HashMap:我们最常用的Map,它根据key的HashCode 值来存储数据,根据key可以直接

  • Java常用工具类—集合排序

    一.集合排序概述 1.主要内容 集合中的基本数据类型排序 集合中的字符串排序 Comparator接口 Comparable接口 回顾: //数组的排序 int[] arr= {2,3,4,5,2,1}; Arrays.sort(arr); 2.集合排序方法 使用Collections类的sort(List list)方法 sort(List list)是根据元素的自然顺序对指定列表按升序进行排序. 二.对基本数据类型和字符串类型进行排序 1.对基本数据类型排序 List中只能存放对象,要想存放

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

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

  • java 数据结构之堆排序(HeapSort)详解及实例

    1 堆排序 堆是一种重要的数据结构,分为大根堆和小根堆,是完全二叉树, 底层如果用数组存储数据的话,假设某个元素为序号为i(Java数组从0开始,i为0到n-1),如果它有左子树,那么左子树的位置是2i+1,如果有右子树,右子树的位置是2i+2,如果有父节点,父节点的位置是(n-1)/2取整.最大堆的任意子树根节点不小于任意子结点,最小堆的根节点不大于任意子结点. 所谓堆排序就是利用堆这种数据结构的性质来对数组进行排序,在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的性质可知,最大的

  • java数据结构排序算法之树形选择排序详解

    本文实例讲述了java数据结构排序算法之树形选择排序.分享给大家供大家参考,具体如下: 这里我们就来说说选择类排序之一的排序:树形选择排序 在简单选择排序中,每次的比较都没有用到上次比较的结果,所以比较操作的时间复杂度是O(N^2),想要降低比较的次数,则需要把比较过程中的大小关系保存下来.树形选择排序是对简单选择排序的改进. 树形选择排序:又称锦标赛排序(Tournament Sort),是一种按照锦标赛的思想进行选择排序的方法.首先对n个记录的关键字进行两两比较,然后在n/2个较小者之间再进

  • Java中的2种集合排序方法介绍

    直接上代码: import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; /** * * <p> * ClassName CollectionsSort * </p> * <p> * Description 主要介绍两种集合的排序算法<br/> * 第一:java.util.Collections.s

  • Java集合和数据结构排序实例详解

    目录 概念 插入排序 直接插入排序 代码实现 性能分析 希尔排序 代码实现 性能分析 选择排序 直接选择排序 代码实现 性能分析 堆排序 代码实现 性能分析 交换排序 冒泡排序 代码实现 性能分析 快速排序 代码实现 性能分析 非递归实现快速排序 代码实现 性能分析 归并排序 归并排序 代码实现 性能分析 非递归实现归并排序 代码实现 性能分析 海量数据的排序问题 总结 概念 排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作. 平时的上下文中,如果提到排序,通常

  • Java集合删除元素ArrayList实例详解

    Java集合删除元素ArrayList实例详解 AbstractCollection集合类中有一个remove方法,该方法为了适配多种不同的集合,允许删除空的元素,看这部分代码的时候产生了疑问,为什么这里直接用it.remove()就直接删除了? public boolean remove(Object o) { Iterator<E> it = iterator(); if (o==null) { while (it.hasNext()) { if (it.next()==null) { i

  • Java集合功能与用法实例详解

    本文实例讲述了Java集合功能与用法.分享给大家供大家参考,具体如下: 本文内容: 什么是集合 Collection Iterator List set Map Collections工具类 首发日期:2018-05-17 什么是集合: 集合是一种新容器,集合可以存储数量不固定的元素(数组的空间是固定的,你申请多少空间以后都不能改变),而集合可以动态的增加空间(有些是空间不够时新建一个足够大的数组再把原来的元素移到新的数组中). 集合的出现解决的几个问题: 存储数量不等的元素. 定义了数据结构,

  • Java集合教程之Collection实例详解

    前言 集合就是一组数的集合,就像是一个容器,但是我们应该清楚的是集合中存放的都是对象的引用,而不是真正的实体.而我们常说的集合中的对象其实指的就是对象的引用. 我们可以把集合理解为一个小型数据库,用于存放数据,我们对集合的操作也就是数据的增删改查,在 Java 中有两个顶层接口 Collection 和 Map 用于定义和规范集合的相关操作.这篇文章主要说一下集合框架中的 Collection 部分. Collection 表示一组对象,这些对象可以是有序也可以是无序的,它提供了不同的子接口满足

  • Java Map的排序实例详解

     Java Map的排序实例详解 要对Map中的key-value键值对进行排序,可以使用Collections类提供的sort方法.该方法允许用户使用自定义的排序方法,可以按键进行排序,或者按值进行排序. 具体代码如下: 1.产生需要的数据 Map<String, Integer> map_Data = new HashMap<String, Integer>(); map_Data.put("A", 98); map_Data.put("B&quo

  • java操作mongoDB查询的实例详解

    java操作mongo查询的实例详解 前言: MongoDB是一个基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用提供可扩展的高性能数据存储解决方案. MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的.他支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型.Mongo最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且

  • java中的interface接口实例详解

     java中的interface接口实例详解 接口:Java接口是一些方法表征的集合,但是却不会在接口里实现具体的方法. java接口的特点如下: 1.java接口不能被实例化 2.java接口中声明的成员自动被设置为public,所以不存在private成员 3.java接口中不能出现方法的具体实现. 4.实现某个接口就必须要实现里面定义的所有方法. 接下来看一个实现接口的案例: package hello;   interface competer{ //定义接口 void set_comp

  • Java Web请求与响应实例详解

    Servlet最主要作用就是处理客户端请求并作出回应,为此,针对每次请求,Web容器在调用service()之前都会创建两个对象,分别是HttpServletRequest和HttpServletResponse.其中HttpServletRequest封装HTTP请求消息,HttpServletResponse封装HTTP响应消息.需要注意的是,Web服务器运行过程中,每个Servlet都会只创建一个实例对象,不过每次请求都会调用Servlet实例的service(ServletRequest

  • C语言数据结构 快速排序实例详解

    C语言数据结构 快速排序实例详解 一.快速排序简介 快速排序采用分治的思想,第一趟先将一串数字分为两部分,第一部分的数值都比第二部分要小,然后按照这种方法,依次对两边的数据进行排序. 二.代码实现 #include <stdio.h> /* 将两个数据交换 */ void swap(int* Ina , int* Inb) { int temp = *Ina; *Ina = *Inb; *Inb = temp; } /* 进行一趟的快速排序,把一个序列分为两个部分 */ int getPart

  • java中Iterator和ListIterator实例详解

    Iterator和ListIterator的作用范围以及关系: (1) Iterator可以用于迭接口List的实现ArrayList,LinkedList以及Map等. (2) ListIterator顾名思义,就是用于迭代List实现ArrayList,LinkedList. (3) 从源码或API文档中可以看出,Iterator为ListIterator的父类. public interface ListIterator<E> extends Iterator<E> { //

随机推荐