从最初的感动开始--JAVA算法【2】--归并和快排
来源:互联网 发布:淘宝的投诉电话是多少 编辑:程序博客网 时间:2024/06/06 01:31
花了半个礼拜火速重温了JAVA基础语法后,终于来到了算法的第一个高潮…排序
首先奉上归并排序的代码:
class Merge { private static Comparable[] aux; public static void merge(Comparable[] a,int lo,int mid,int hi){ //merge the a[lo..mid] and a[mid+1..hi] int i= lo, j = mid +1; //copy the array for (int k = lo; k<=hi; k++){ aux[k] = a[k]; } for (int k = lo; k<= hi; k++){ if (i>mid) a[k] = aux[j++]; else if (j>hi) a[k]=aux[i++]; else if (less(aux[j],aux[i])) a[k]=aux[j++]; else a[k] = aux[i++]; } } private static boolean less(Comparable comparable, Comparable comparable0) { return comparable.compareTo(comparable0)<0; } public static void sort(Comparable[] a){ aux = new Comparable[a.length]; sort(a,0,a.length-1); } private static void sort(Comparable[] a, int lo, int hi) { if (hi<=lo) return; int mid = lo+ (hi-lo)/2; sort(a, lo, mid); sort(a, mid+1, hi); merge(a, lo, mid, hi); }}
归并排序的高潮在于分而治之,这是一种贯穿程序算法设计始终的思想。
Merge()函数中,分别构造两个新指针,一个从数组头部开始(i),一个从数组的中间开始(j),分别和k元素比较,那边小就动哪边,一直到循环退出。
接下来是经典的原始快排:
class Quick { public static void sort(Comparable[] a){ StdRandom.shuffle(a); sort(a,0,a.length - 1); } private static void sort(Comparable[] a, int lo, int hi) { if (hi <= lo) return; int j =partition(a, lo, hi); sort(a, lo, j-1); sort(a, j+1, hi); } private static int partition(Comparable[] a, int lo, int hi) { int i = lo, j = hi + 1; Comparable v = a[lo]; while(true){ while (less(a[++i],v)) if (i == hi) break; while (less(v, a[--j])) if (j == lo) break; if (i >= j) break; exch(a, i, j); } exch(a, lo, j); return j; } private static boolean less(Comparable comparable, Comparable comparable0) { return comparable.compareTo(comparable0)<0; } private static void exch(Comparable[] a, int i, int j) { Comparable t = a[i]; a[i] = a[j]; a[j] = t; }}
快排的思想在于…好吧,同样是分而治之,这点从第二个sort()函数的迭代结构便可知晓。
和归并相比,其优势在于其潜在的元素交换更少,从而更节省资源和时间。此外,也不需要再构建一个数组做中间变量(归并中的aux全局变量的功能)。
值得注意的是,这个快排的代码已经做了优化。
在做切分的partition()函数中,左扫描的终止条件为 !less(a[++i],v), 即左边大于等于时v时,终止左扫描开始右扫描。 而右扫描的终止条件为 !less(v, a[–j]),即右边小于等于v时,终止右扫描,如果在此时左右扫描都还没到头时,交换左右扫描停止时所指向的位置(exch(a, i, j))。
注意,这里左右扫描停止的条件,包含“等于”。如果这个条件去掉,只有当左边大于v,右边小于v时,才会停止扫描,那么和v相等的元素在一次切分后,仍然散落在数组各处,在后续的切分过程中,这些值仍将一次次地执行比较和位移,极大浪费了之前的比较操作所付出的成本。
然而即使已经做出了改进,与v值相等的元素,依然会被做为子数组,在切分完成后,被划入子数组中,再次参与到下一步的排序。为了避免这点,出现了三向快排:
class Quick3way { private static void sort(Comparable[] a, int lo, int hi){ if (hi <= lo) return; int lt = lo, i = lo+1, gt = hi; Comparable v = a[lo]; while (i <= gt){ int cmp = a[i].compareTo(v); if (cmp<0) exch(a, lt++, i++); else if (cmp>0) exch(a, i, gt--); else i++; } sort(a, lo, lt-1); //skip the elements, which has the same value of v sort(a, gt+1, hi); //that will save lots of time } public static void sort(Comparable[] a){ sort(a,0,a.length-1); } private static void exch(Comparable[] a, int i, int j) { Comparable t = a[i]; a[i] = a[j]; a[j] = t; }}
三向快排多了一个指针,它标记了与v值相等的元素,这些元素在本次切分完成后,不再参与到下一次的排序,从而大大缩减了后续的操作步骤。
理论上,没有任何基于比较的排序算法,能够让比较次数少于N*lgN,然而三向快排利用了先期比较时所获得的信息,从而在对存在大量重复数据进行排序时,能以更少的比较步骤完成排序工作。
- 从最初的感动开始--JAVA算法【2】--归并和快排
- 从最初的感动开始--JAVA算法【1】--折半查找
- 从最初的感动开始--JAVA算法【3】--不简单的红黑树
- 数据结构算法-快排和归并
- 归并、快排算法的学习
- 快排和归并排序的比较
- 快排和归并的简单概论
- C语言实现快排、归并排序、快排改进算法的递归和非递归算法
- 归并与快排算法
- 从最初的感动开始--数值计算【1】--梯度下降与牛顿法
- 快排、堆排和归并排序的Python实现
- 快排和归并排序
- 快排和归并算法比较之swap函数
- 算法整理-排序(归并和快排)
- 算法从写出最简单的快排开始找到自信
- Java实现的排序算法及比较 [冒泡,选择,插入,归并,希尔,快排]
- 排序及选择算法的java实现(一)选择、冒泡、插入、希尔、归并、快排
- 常用的排序算法 插入-冒泡-选择-归并-快排
- 一些有用的内容与链接整理【持续更新】
- POJ 3376 Finding Palindromes
- linux下nc神器简介
- Kail下如何关闭防火墙
- Linux下的目录结构、挂载与分区
- 从最初的感动开始--JAVA算法【2】--归并和快排
- 布局的小分析
- 链表的基本操作
- JAVA零碎知识点
- php是世界上最好的语言
- 创建定时器
- Android性能优化--listview 优化机制
- Odoo 多对多界面控件(many2many Widget)
- 线段树