数据结构-高级排序
来源:互联网 发布:淘宝网男士皮欧上衣 编辑:程序博客网 时间:2024/06/02 04:21
简述
高级排序算法:希尔排序和快速排序。
其执行效率分别为希尔排序的O(N*(logN)^2)和快速排序的O(N*logN)。
归并排序相较于简单排序中冒泡排序、选择排序和插入排序的执行速度要快,但是需要原始数据空间的两倍。而希尔排序和快速排序不需要大量的辅助空间。
具体实现
希尔排序
package com.jikefriend.arraysort;/** * 希尔排序,其基于插入排序,不适合大规模数据排序 * * 希尔排序通过加入插入排序中元素之间的间隔,并在这些有间隔的元素中进行插入排序, * 从而使数据项能大跨度地移动。当这些数据项排过一趟序后,希尔排序算法减小数据项 * 的间隔再进行排序,依此进行下去 * * 进行这些排序时数据项之间的间隔称为增量 * 对于10个元素,通过 h = h * 3 + 1 确定间隔,有4和1 * 间隔为4时对(0,4,8)(1,5,9)(2,6)(3,7)分别排序,实际不是按此分组排序, * 而是先排第一组的前两个数据项,然后是第二组的前两个数据项,以此类推, * 当所有组的前两个数据项有序后,算法返回再对三个数据项的组进行排序,因此4-增量的实际执行顺序是 * (0,4)(1,5)(2,6)(3,7)(0,4,8)(1,5,9) * 间隔为1时,排序后,算法结束 * * 排序间隔序列的子数组,逐渐减小间隔,直至为1 * 注意:后续的排序不撤销前期排序的结果 */public class ShellSort { private int[] theArray; private int nElems; public ShellSort(int max) { theArray = new int[max]; nElems = 0; } public void insert(int value) { theArray[nElems++] = value; } public void display() { System.out.print("A="); for (int i = 0; i < nElems; i++) System.out.print(theArray[i] + " "); System.out.println(); } public void shellSort() { int inner, outer; int temp; int h = 1; while (h <= nElems / 3) //找到间隔序列的h初始值 h = h * 3 + 1; while (h > 0) //根据公式 h = (h - 1) / 3 递减,直到h = 1 { for (outer = h; outer < nElems; outer++) //以h为间隔对数组排序 { temp = theArray[outer]; inner = outer; while (inner > h - 1 && theArray[inner - h] >= temp) { theArray[inner] = theArray[inner - h]; inner -= h; } theArray[inner] = temp; } h = (h - 1) / 3; } } public static void main(String[] args) { int maxSize = 10; ShellSort arr = new ShellSort(maxSize); for (int i = 0; i < maxSize; i++) { arr.insert((int)(Math.random() * 99)); } arr.display(); arr.shellSort(); arr.display(); }}
划分
package com.jikefriend.arraysort;/** * 划分 * 划分数据是把数据分成两组, * 使所有关键字大于特定值的数据项在一组, * 所有关键字小于特定值的数据项在一组。 * * 注意: * 划分是不稳定的,即每一组中的数据项并不是按照它原来的顺序排列的。 * 事实上,划分往往会颠倒组中一些数据项的顺序。 */public class PartitionArray { private int[] theArray; private int nElems; public PartitionArray(int max) { theArray = new int[max]; nElems = 0; } public void insert(int value) { theArray[nElems++] = value; } public int size() { return nElems; } public void display() { for (int i = 0; i < nElems; i++) System.out.print(theArray[i] + " "); System.out.println(); } /** * 划分算法由两个指针开始工作,分别指向数组的两头。 * 左边的指针向右移动,右边的指针向左移动。 * @param left * @param right * @param pivot * @return */ public int partition(int left, int right, int pivot) { int leftPtr = left - 1; int rightPtr = right + 1; while (true) { /** leftPtr当前的值如果比特定值小,则继续右移,因为这个数据项已经处在正确的一侧,直至找到比特定值大的数据项停止移动 */ while (leftPtr < right && theArray[++leftPtr] < pivot) //找出比特定值大的数据项 ; /** rightPtr当前的值如果比特定值大,则继续左移,因为这个数据项已经处在正确的一侧,直至找到比特定值小的数据项停止移动 */ while (rightPtr > left && theArray[--rightPtr] > pivot) //找出比特定值小的数据项 ; /** 当两个while都退出循环时,leftPtr和rightPtr都指向在数组的错误一方位置上的数据,交换这两个数据 */ if (leftPtr >= rightPtr) //如果两个指针相遇,则划分结束 break; else //如果两个指针还没有相遇,则交换两个数据项 swap(leftPtr, rightPtr); //使小的数据项在特定值的左侧,大的数据项在右侧 } return leftPtr; } private void swap(int dex1, int dex2) { int temp = theArray[dex1]; theArray[dex1] = theArray[dex2]; theArray[dex2] = temp; } public static void main(String[] args) { int maxSize = 16; PartitionArray arr = new PartitionArray(maxSize); for (int i = 0; i < maxSize; i++) { arr.insert((int)(Math.random() * 199)); } arr.display(); int pivot = 99; System.out.print("Pivot is " + pivot); int size = arr.size(); int partDex = arr.partition(0, size - 1, pivot); System.out.println(", Partition is at index " + partDex); arr.display(); }}
快速排序
使用最右端数据项作为枢纽值
package com.jikefriend.arraysort;/** * 快速排序,O(N*logN),最坏O(N^2) * 基本步骤: * 1、使用划分算法把数组或子数组划分成左边(较小的关键字)的一组和右边(较大的关键字)的一组; * 2、调用自身对左边的一组进行排序; * 3、再次调用自身对右边的一组进行排序。 * * 基值情况:当数组只有一个数据项时,认为已经有序。 * * 目标值(枢纽)的选取思想: * 1、应该选择具体的一个数据项的关键字的值作为枢纽; * 2、可以选择任意一个数据项作为枢纽。为了简便,我们假设总是选择划分的子数组最右端的数据项作为枢纽; * 3、划分完成之后,如果枢纽被插入到左右子数组之间的分界处,那么枢纽就落在排序之后的最终位置上。 */public class QuickSort1 { private int[] theArray; private int nElems; public QuickSort1(int max) { theArray = new int[max]; nElems = 0; } public void insert(int val) { theArray[nElems++] = val; } public void display() { for (int i = 0; i < nElems; i++) System.out.print(theArray[i] + " "); System.out.println(); } public void quickSort() { recQuickSort(0, nElems - 1); } private void recQuickSort(int left, int right) { if (right - left <= 0) //当数组的大小 <= 1时,认为已经有序 return; else { int pivot = theArray[right]; //选择数组的最右端数据项作为枢纽值 int partition = partition(left, right, pivot); //划分数组,使小于枢纽值的数据项在左边子数组,大于枢纽值的在右边子数组 recQuickSort(left, partition - 1); //递归调用该方法对左边数组排序 recQuickSort(partition + 1, right); //递归调用该方法对右边数组排序 } } /** * 根据枢纽值划分数组 * @return 完成划分后枢纽值的位置 */ private int partition(int left, int right, int pivot) { int leftPtr = left - 1; int rightPtr = right; while (true) { while (theArray[++leftPtr] < pivot) //由于枢纽值选取数组最右端,所以leftPtr不会发生数据越界 ; while (rightPtr > 0 && theArray[--rightPtr] > pivot) ; if (leftPtr >= rightPtr) break; else swap(leftPtr, rightPtr); } swap(leftPtr, right); //right是枢纽值所在的位置,即数组最右端,完成划分后,将枢纽值保存在分界处 return leftPtr; } private void swap(int dex1, int dex2) { int temp = theArray[dex1]; theArray[dex1] = theArray[dex2]; theArray[dex2] = temp; } public static void main(String[] args) { int maxSize = 10; QuickSort1 arr = new QuickSort1(maxSize); for (int i = 0; i < maxSize; i++) { arr.insert((int)(Math.random() * 99)); } arr.display(); arr.quickSort(); arr.display(); }}
使用三数据项取中法选取枢纽值
package com.jikefriend.arraysort;/** * 快速排序,O(N*logN),最坏O(N^2) * “三数据项取中”划分 * 找到数组里第一个、最后一个以及中间位置数据项的居中数据项值,作为枢纽值。 * * 由于在选择枢纽的同时,对该三个数据项进行了排序,保证了最左端的数据项小于枢纽值, * 最右端的大于枢纽值,两端指针避免的越界。 */public class QuickSort2 { private int[] theArray; private int nElems; public QuickSort2(int max) { theArray = new int[max]; nElems = 0; } public void insert(int val) { theArray[nElems++] = val; } public void display() { for (int i = 0; i < nElems; i++) System.out.print(theArray[i] + " "); System.out.println(); } public void quickSort() { recQuickSort(0, nElems - 1); } private void recQuickSort(int left, int right) { int size = right - left + 1; if (size < 10) //当数组的大小 < 10时,使用插入排序 insertionSort(left, right); else { int pivot = medianOf3(left, right); //三数据项取中来选取枢纽值 int partition = partition(left, right, pivot); //划分数组,使小于枢纽值的数据项在左边子数组,大于枢纽值的在右边子数组 recQuickSort(left, partition - 1); //递归调用该方法对左边数组排序 recQuickSort(partition + 1, right); //递归调用该方法对右边数组排序 } } private int medianOf3(int left, int right) { int center = (left + right) / 2; if (theArray[left] > theArray[center]) //对left和center排序 swap(left, center); if (theArray[left] > theArray[right]) //对left和right排序 swap(left, right); if (theArray[center] > theArray[right]) //对center和right排序 swap(center, right); swap(center, right - 1); //将选定的枢纽值放到数组最右端-1 return theArray[right - 1]; } /** * 根据枢纽值划分数组 * @return 完成划分后枢纽值的位置 */ private int partition(int left, int right, int pivot) { int leftPtr = left; int rightPtr = right - 1; while (true) { while (theArray[++leftPtr] < pivot) //由于枢纽值选取数组最右端,所以leftPtr不会发生数据越界 ; while (theArray[--rightPtr] > pivot) ; if (leftPtr >= rightPtr) break; else swap(leftPtr, rightPtr); } swap(leftPtr, right - 1); //right - 1是枢纽值所在的位置,即数组最右端-1,完成划分后,将枢纽值保存在分界处 return leftPtr; } private void swap(int dex1, int dex2) { int temp = theArray[dex1]; theArray[dex1] = theArray[dex2]; theArray[dex2] = temp; } /** * 插入排序,处理小划分 */ private void insertionSort(int left, int right) { int in, out; for (out = left + 1; out <= right; out++) { int temp = theArray[out]; in = out; while (in > left && theArray[in -1] >= temp) { theArray[in] = theArray[in - 1]; --in; } theArray[in] = temp; } } public static void main(String[] args) { int maxSize = 10; QuickSort2 arr = new QuickSort2(maxSize); for (int i = 0; i < maxSize; i++) { arr.insert((int)(Math.random() * 99)); } arr.display(); arr.quickSort(); arr.display(); }}
摘自《Java数据结构与算法(第二版)》 [美] Robert Lafore 著
0 0
- 数据结构-高级排序
- 数据结构-高级排序
- Java数据结构与算法--高级排序
- .net 数据结构与算法基础:高级排序
- java数据结构与算法-高级排序-基数排序
- 数据结构之高级排序<希尔排序、快速排序>
- Java数据结构和算法-高级排序(1-希尔排序)
- java数据结构与算法-高级排序-归并排序
- java数据结构与算法-高级排序-希尔排序
- java数据结构与算法-高级排序-快速排序
- java数据结构与算法-高级排序-堆排序
- 数据结构和算法学习(7)-高级排序
- 数据结构与算法之高级排序(希尔/堆)<十一>
- 数据结构与算法之高级排序(快速/归并)<十二>
- 高级数据结构与算法:Week 1, 内排序(上)
- 高级数据结构
- 高级数据结构
- 数据结构-简单排序
- Hi3516a 调试GMM 出现问题
- 第七周项目5-排队看病模拟
- 第四周项目3(1)-单链表应用 逆置单链表
- 求一个整数数组的连续子数组的最大和.
- memcache 缓存 分布式锁原理
- 数据结构-高级排序
- URI和URL的区别
- Java基础学习总结(69)——匿名内部类与Lambda表达式
- Atom编辑器小试
- 关于MVC、MVVM等一大堆思想
- SpringMVC中使用Interceptor拦截器
- Qt之对应用实现截屏并保存
- ubtuntu 14.04 usb port not working
- Hibernate 简单 的 增删改查 实例