算法——排序之简单排序
来源:互联网 发布:批量注册淘宝小号论坛 编辑:程序博客网 时间:2024/06/14 04:17
排序是将一组对象按照某个逻辑顺序重新排列的过程。现在计算机的广泛使用使得数据无处不在,整理数据就变得非常重要了。而整理数据的第一步往往都是进行排序。
简单排序
冒泡排序
原理:
将所有临近的两个的对象按照某个逻辑一一进行比较,通常是由大到小或小到大,比较之后交换两个对象的位置。
反复操作,最终即可排序成功。
如上图所示,我们发现,进行一次循环,冒泡排序只能确定一个对象的位置。第一次循环只能够确定一个对象的位置。所以我们需要多少次循环呢?我们就可以的得出,我们总共需要n-1次循环。因为n-1次循环能确定n-1个对象的位置,这时候自然最后一个对象的位置也确定了。
代码如下:
public static void sort(Comparable[] a) {for (int i = 0; i < a.length - 1; i++) {for (int j = 0; j < a.length - 1; j++) {if (less(a[j + 1], a[j])) {swap(a, j, j + 1);}}}}实际也就是依靠两层循环,外层控制循环次数,内层逐个进行比较。
冒泡排序的优点就是简单,空间复杂度低。缺点就是慢!无用功多。
时间复杂度O(n^2)
选择排序
原理:
首先找到当前数组中最小的元素,将这个元素和第一个元素进行交换位置。其次,在剩下的数组中找到最小的元素,将它和数组中第二个元素进行位置的交换。依次类推,就可以达到排序的效果。简单来说就是每次都选最小的那个,放在前面。
代码:
public static void sort(Comparable[] a) {for (int i = 0; i < a.length - 1; i++) {int minIndex = i;for (int j = i + 1; j < a.length; j++) {if (less(a[j], a[minIndex])) {minIndex = j;}}swap(a, minIndex, i);}}
选择排序将数组分成两个部分,已经排序好的和未排序两部分。每次都从未排序部分中找到最小的元素,增加到排好序的末尾。
同样的,外层循环控制次数,内层循环找到最小的元素。外层循环,因为只要找到n-1个元素的位置,第n个元素的位置就直接确定了。所以外层循环需要n-1次。我个人认为选择排序是最简单理解的排序之一。
时间复杂度O(n^2)
插入排序
插入排序就和平常打扑克牌一样。整理扑克牌的一般使用的就是插入排序。整理方法是一张一张来,将每一张牌插入其他已经有序的牌中的适当位置。当然,在数组操作中,如果需要给某个元素插入,腾出空间,则需要将其他元素向后移动一位。
代码“:
public static void sort(Comparable[] a) {for (int i = 1; i < a.length; i++) {for (int j = i - 1; j >= 0 && less(a[j+1], a[j]); j--) {swap(a, j, j + 1);}}}这个代码简洁,但是却不容易让人看懂。不个人不推荐这么做。而是应该将思路表达的清晰。
改变:
public static void sort(Comparable[] a) {for (int i = 1; i < a.length; i++) {int position = findPosition(a, i); // 找到应该插入的位置Comparable tempI = a[i];for (int j = i - 1; j >= position; j--) { // 为插入的位置腾出空间,向后挪动a[j + 1] = a[j];}a[position] = tempI; // 插入值}}public static int findPosition(Comparable[] a, int i) {for (int j = i - 1; j >= 0; j--) {if (less(a[j], a[i])) return j + 1;}return 0;}
和选择排序不同,插入排序所需的时间和取决于输入元素的初始顺序。对一个已经接近有序的数组进行排序,会比对顺序随机的数组进行排序快得多。
平均时间复杂度:O(n^2)。最好情况时间复杂度O(n)。
插入排序对于部分有序的数组来说非常高效,这是它最大的优点。
希尔排序
希尔排序是对插入排序的一个优化。对于大规模的乱序数组,插入排序会比较缓慢,因为他需要慢慢的向前找到位置,所以元素只能一点一点的从数组中移动到另一端。
希尔排序本质就是分组的插入排序,但是它并不需要一个一个比较,而是能将元素一下子移到一个比较远的地方。
原理:
先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比前两种方法有较大提高。
上图中,方框指向的是同一组,也就是将同一组数据排序。当分组越来越少,一组中元素越来越多的时候,排序就基本完成了。而最终,当所有元素都在同一组中的时候,就是简单插入排序。因为这个时候数组已经接近有序了,所以排序起来非常快。
代码:
public static void sort(Comparable[] a) {int gap = 1;while (gap < a.length /3) gap = 3*gap + 1;while (gap >= 1) {for (int i = 0; i < gap; i++) {for (int j = i + gap; j < a.length; j += gap) {int position = findPosition(a, i, j, gap);Comparable tempJ = a[j];for (int k = j - gap; k >= position; k -= gap) {a[k + gap] = a[k];}a[position] = tempJ;}}gap /= 3;}}public static int findPosition(Comparable[] a, int begin, int current, int gap) {for (int i = current - gap; i >= begin; i -= gap) {if (less(a[i], a[current])) return i + gap;}return begin;}和插入排序非常类似,仅仅是分组的插入排序。
比较:
代码:
public static void main(String[] args) { final int NUM = 10000; Integer[] a1 = new Integer[NUM]; Integer[] a2 = new Integer[NUM]; Integer[] a3 = new Integer[NUM]; Integer[] a4 = new Integer[NUM]; for (int i = 0; i < NUM; i++) { a1[i] = (int)(Math.random() * NUM); a2[i] = a1[i]; a3[i] = a1[i]; a4[i] = a1[i]; } long startTime; long endTime; /* * 交换 * */ startTime = System.currentTimeMillis(); //获取开始时间 switchSort.sort(a2); assert isSorted(a2); endTime = System.currentTimeMillis(); System.out.println("交换排序cost: " + (endTime - startTime) + " ms"); /* * 插入 * */ startTime = System.currentTimeMillis(); //获取开始时间 InsertSort.sort(a3); assert isSorted(a3); endTime = System.currentTimeMillis(); System.out.println("插入排序cost: " + (endTime - startTime) + " ms"); /* * 冒泡 * */ startTime = System.currentTimeMillis(); //获取开始时间 bubbleSort.sort(a1); assert isSorted(a1); endTime = System.currentTimeMillis(); System.out.println("冒泡排序cost: " + (endTime - startTime) + " ms"); /* * shell * */ startTime = System.currentTimeMillis(); //获取开始时间 ShellSort.sort(a4); assert isSorted(a4); endTime = System.currentTimeMillis(); System.out.println("希尔排序cost: " + (endTime - startTime) + " ms");}运行多次,我们会发现:
当数据量不大的时候,插入排序比交换排序快。而数据量大起来,交换排序就比插入排序更加快了。
当然,如果数组是接近有序的,插入排序的性能会非常强大。
冒泡排序比较缓慢。
而希尔排序的性能非常不错。即使数据量非常大,希尔排序的性能也是不错的。希尔排序的平均时间复杂度是O(n^1.3)左右。相对简单插入排序来说确实是极大的提升。并且希尔排序的代码量并不大。
- 算法——排序之简单排序
- 排序算法之—简单排序
- 排序算法之选择排序——简单选择排序
- 简单排序算法之——插入排序
- 算法之选择排序——简单选择排序
- 排序算法之简单排序
- 排序算法之简单排序
- 五、排序算法之简单算法——冒泡排序、简单选择排序和直接插入排序
- 算法之简单排序
- 排序算法——简单选择排序
- 排序——简单排序算法
- 排序算法——简单选择排序
- 排序算法——简单选择排序
- 算法 排序算法之简单选择排序
- 排序算法之简单算法——java实现
- Java排序算法总结之(三)——选择排序(简单选择排序、堆排序)
- 排序算法之简单选择排序
- 排序算法入门之简单选择排序
- 【Java EE】--JavaServer Faces 02
- Java 内存区域和GC机制
- CalendarUtil 日期操作工具类
- HTTP Status 400
- 第20章 连续时间信号频域分析及小结
- 算法——排序之简单排序
- Docker技术文档
- HDU 1070---Milk (JAVA解答)
- eclipse 和 IDEA 设置虚拟机启动参数
- 虚拟机搭建CDH-第七讲-安装CM
- [转载]复杂网络分析库NetworkX学习笔记(1):入门
- 【CentOS】ifconfig command not found
- Python-函数(三)
- 自定义LinearLayout并搭配流式布局,实现商城app商品规格选择View