Java排序算法以及算法改进总结(冒泡、选择、插入、归并、快速排序)
2017-10-09 19:49
597 查看
算法复习,代码是最好的说明!
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
取出下一个元素,在已经排序的元素序列中从后向前扫描
如果该元素(已排序)大于新元素,将该元素移到下一位置
重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
将新元素插入到该位置后
重复步骤2~5
申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
设定两个指针,最初位置分别为两个已经排序序列的起始位置
比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针到达序列尾
将另一序列剩下的所有元素直接复制到合并序列尾
把所有比基准值小的元素放在基准前面,所有比基准值大的元素放在基准的后面(相同的数可以到任一边),这个称为分区(partition)操作。
对每个分区递归地进行步骤1~2,递归的结束条件是序列的大小是0或1,这时整体已经被排好序了。
参考链接:
http://www.cnblogs.com/eniac12/p/5329396.html#s5
http://blog.csdn.net/morewindows/article/details/6668714
http://blog.csdn.net/hguisu/article/details/7776068
http://www.blogjava.net/killme2008/archive/2010/09/08/quicksort_optimized.html
如有错误,欢迎纠正!
一、冒泡排序:
算法:
比较相邻的元素。如果第一个比第二个大,就交换他们两个。对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
分析:
平均 | 最好 | 最坏 | 辅助存储 | 稳定性 |
O(n^2) | O(n) | O(n^2) | O(1) | 稳定 |
代码:
/** * 冒泡排序 * @param array */ void bubbleSort_1(int[] array){ for (int i = array.length-1; i >0 ; i--) { for (int j = 0; j <i ; j++) { if (array[j]>array[j+1]){ swap(array,j,j+1); } } } } /** * 冒泡排序改进,标志某一趟排序过程中是否有数据交换,如果进行某一趟排序时并没有进行数据交换,则说明数据已经按要求排列好,可立即结束排序,避免不必要的比较过程 * @param array */ void bubbleSort_2(int[] array){ boolean isSwaped; for (int i = array.length-1; i >0 ; i--) { isSwaped = false; for (int j = 0; j <i ; j++) { if (array[j]>array[j+1]){ swap(array,j,j+1); isSwaped = true; } } if (!isSwaped) break; } } /** * 冒泡排序改进,设置一个pos指针,pos后面的数据在上一轮排序中没有发生交换,下一轮排序时,就对pos之后的数据不再比较 * @param array */ void bubbleSort_3(int[] array){ int end = array.length - 1; while (end>0) { int pos = 1; for (int j = 1; j <=end; j++) { if (array[j-1] > array[j]) { swap(array, j-1, j); pos = j; } } end = pos - 1; } } /** * 鸡尾酒排序,也叫定向冒泡排序,是冒泡排序的一种改进。此算法与冒泡排序的不同处在于从低到高然后从高到低,而冒泡排序则仅从低到高去比较序列里的每个元素。他可以得到比冒泡排序稍微好一点的效能。 * @param array */ void bubbleSort_4(int[] array){ int left = 0; int right = array.length-1; while (left < right){ for (int i = left; i <right ; i++) { if (array[i] > array[i+1]) swap(array,i,i+1); } right--; for (int i = right; i >left ; i--) { if (array[i] < array[i-1]) swap(array,i,i-1); } left++; } } void swap(int[] array,int i,int j){ int temp = array[i]; array[i] = array[j]; array[j] = temp; }
二、选择排序:
算法:
每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。分析:
平均 | 最好 | 最坏 | 辅助存储 | 稳定性 |
O(n^2) | O(n^2) | O(n^2) | O(1) | 不稳定 |
代码:
/** * 选择排序 * @param array */ void selectionSort_1(int[] array){ for (int i = 0; i <array.length-1 ; i++) { int min = i; for (int j = i+1; j < array.length; j++) { if (array[j]<array[min]){ min = j; } } if (min!=i) swap(array,min,i); } } /** * 选择排序改进,每趟排序确定两个最值——最大值与最小值,这样就可以将排序趟数缩减一半。 * @param array */ void selectionSort_2(int[] array){ int left = 0; int right = array.length-1; while (left<right){ int min = left; int max = right; for (int i = left; i <=right; i++) { if (array[i]<array[min]) min = i; if (array[i]>array[max]) max = i; } if (min!=left) swap(array,min,left); if (max!=right&&max!=left) swap(array,max,right); left++; right--; } }
三、插入排序:
1、直接插入排序:
算法:
从第一个元素开始,该元素可以认为已经被排序取出下一个元素,在已经排序的元素序列中从后向前扫描
如果该元素(已排序)大于新元素,将该元素移到下一位置
重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
将新元素插入到该位置后
重复步骤2~5
分析:
平均 | 最好 | 最坏 | 辅助存储 | 稳定性 |
O(n^2) | O(n) | O(n^2) | O(1) | 稳定 |
代码:
/** * 插入排序,写法一 * @param array */ void insertionSort_1(int[] array){ for (int i = 1; i < array.length; i++) { int get = array[i]; int j = i-1; while (j>=0&&array[j]>get){ array[j+1] = array[j]; j--; } array[j+1] = get; } } /** * 插入排序,写法二 * @param array */ void insertionSort_2(int[] array){ for (int i = 1; i < array.length; i++) { for (int j = i; j >0 ; j--) { if (array[j]<array[j-1]) swap(array,j,j-1); else break; } } }
2、二分插入排序:
算法:
利用二分法的思想对插入排序进行改进。分析:
平均 | 最好 | 最坏 | 辅助存储 | 稳定性 |
O(n^2) | O(nlogn) | O(n^2) | O(1) | 不稳定 |
代码:
/** * 插入排序改进二分法插入 * @param array */ void insertionSortDichotomy(int[] array){ for (int i = 1; i < array.length; i++) { int get = array[i]; int left = 0; int right = i - 1; while (left<=right){ int mid = (left+right)/2; if (array[mid]<get) left = mid + 1; else right = mid - 1; } for (int j = i-1; j >=left; j--) { array[j+1] = array[j]; } array[left] = get; } }
3、希尔插入排序:
算法:
先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量 =1( < …<d2<d1),即所有记录放在同一组中进行直接插入排序为止。分析:
平均 | 最好 | 最坏 | 辅助存储 | 稳定性 |
O(n^2) | O(n^1.3) | O(n^2) | O(1) | 不稳定 |
代码:
/** * 插入排序改进希尔排序,写法一 * @param array */ void shellSort_1(int[] array){ for (int gap = array.length/2; gap >0 ; gap/=2) { for (int i = 0; i < gap; i++) { for (int j = i+gap; j < array.length; j+=gap) { int get = array[j]; int k = j-gap; while (k>=0&&array[k]>get){ array[k+gap]=array[k]; k-=gap; } array[k+gap] = get; } } } } /** * 插入排序改进希尔排序,写法二 * @param array */ void shellSort_2(int[] array){ for (int gap = array.length/2; gap >0 ; gap/=2) { for (int i = 0; i < gap; i++) { for bc8d (int j = i+gap; j < array.length; j+=gap) { for (int k = j; k >=gap ; k-=gap) { if (array[k]<array[k-gap]) swap(array,k,k-gap); else break; } } } } }
四、归并排序:
算法:
归并排序的实现分为递归实现与非递归(迭代)实现。归并排序算法主要依赖归并(Merge)操作,归并操作指的是将两个已经排序的序列合并成一个序列的操作申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
设定两个指针,最初位置分别为两个已经排序序列的起始位置
比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针到达序列尾
将另一序列剩下的所有元素直接复制到合并序列尾
分析:
平均 | 最好 | 最坏 | 辅助存储 | 稳定性 |
O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 稳定 |
代码:
/** * 将两个已经排序的序列合并成一个序列的操作 * @param array * @param left * @param mid * @param right */ void merge(int[] array,int left,int mid,int right){ int[] temp = new int[right-left+1]; int index = 0; int i = left; int j = mid+1; while (i<=mid&&j<=right) temp[index++] = array[i] <= array[j] ? array[i++] : array[j++]; while (i<=mid) temp[index++] = array[i++]; while (j<=right) temp[index++] = array[j++]; for (int k = 0; k <right-left+1; k++) array[left+k] = temp[k]; } /** * 递归实现 * @param array * @param left * @param right */ void MergeSortRecursion(int[] array,int left,int right){ if (left==right) return; int mid = (left+right)/2; MergeSortRecursion(array,left,mid); MergeSortRecursion(array,mid+1,right); merge(array,left,mid,right); } /** * 非递归实现 * @param array */ void MergeSortIteration(int[] array){ int left,mid,right; for (int i = 1; i < array.length; i*=2) { left = 0; while (left+i < array.length){ mid = left + i - 1; right = mid + i < array.length ? mid + i : array.length - 1; merge(array,left,mid,right); left = right + 1; } } }
五、快速排序:
算法:
从序列中挑出一个元素,作为"基准"(pivot)。把所有比基准值小的元素放在基准前面,所有比基准值大的元素放在基准的后面(相同的数可以到任一边),这个称为分区(partition)操作。
对每个分区递归地进行步骤1~2,递归的结束条件是序列的大小是0或1,这时整体已经被排好序了。
分析:
平均 | 最好 | 最坏 | 辅助存储 | 稳定性 |
O(nlogn) | O(nlogn) | O(n^2) | O(nlogn) | 不稳定 |
代码:
/** * * @param array * @param left * @param right * @return */ int partition_1(int[] array, int left, int right){ int pivot = array[right]; int tail = left-1; for (int i = left; i < right; i++) { if (array[i] < pivot) swap(array,++tail,i); } swap(array,++tail,right); return tail; } /** * 改进将pivot的选择随机化,不再是固定选择左端点,或采用三支取中 * @param array * @param left * @param right * @return */ int partition_2(int[] array, int left, int right){ swap(array,right, left+new Random().nextInt(right-left+1)); int pivot = array[right]; int tail = left-1; for (int i = left; i < right; i++) { if (array[i] < pivot) swap(array,++tail,i); } swap(array,++tail,right); return tail; } /** * 改进使用两个索引i和j,分别从左右两端进行扫描,i扫描到大于等于pivot的元素就停止,j扫描到小于等于pivot的元素也停止,交换两个元素,持续这个过程直到两个索引相遇,此时的pivot的位置就落在了j,然后交换pivot和j的位置 * @param array * @param left * @param right * @return */ int partition_3(int[] array, int left, int right){ swap(array,right, left+new Random().nextInt(right-left+1)); int pivot = array[right]; int i = left - 1; int j = right; while (true){ do { i++; }while (i<=right&&array[i]<pivot); do { j--; }while (j>=left&&array[j]>pivot); if (j < i) break; swap(array,i,j); } swap(array,++j,right); return j; } /** * * @param array * @param left * @param right */ void quickSort(int[] array, int left, int right){ if (left>=right) return; int pivot_index = partition_3(array,left,right); quickSort(array,left,pivot_index-1); quickSort(array,pivot_index+1,right); }
参考链接:
http://www.cnblogs.com/eniac12/p/5329396.html#s5
http://blog.csdn.net/morewindows/article/details/6668714
http://blog.csdn.net/hguisu/article/details/7776068
http://www.blogjava.net/killme2008/archive/2010/09/08/quicksort_optimized.html
如有错误,欢迎纠正!
相关文章推荐
- 数据结构(C#)--冒泡、插入、快速、堆、归并、希尔、选择各种排序排序过程比较以及各种排序的所用时间的对比
- 10种排序算法总结(冒泡、选择、插入、希尔、归并、快速、堆、拓扑、锦标赛、基数)
- 10种排序算法总结(冒泡、选择、插入、希尔、归并、快速、堆、拓扑、锦标赛、基数)
- java排序算法(冒泡,插入,选择,快速,堆,归并,希尔,基数)
- 冒泡、鸡尾酒、选择、插入、归并、快速排序的C++程序
- 十种排序算法总结(冒泡、插入、选择、希尔、归并、堆、快速,计数,桶,基数)
- C++排序算法总结(冒泡、插入、选择、希尔、归并、快速、堆)
- php四种基础算法:冒泡,选择,插入和快速排序法
- 常用排序算法总结(插入、冒泡、快速,堆、选择、希尔、归并)
- 常见排序算法总结与实现(冒泡、插入、选择、希尔、堆排序、归并、快排)
- 排序算法整合(冒泡,插入,选择,归并算法)
- java实现选择、插入、归并、快速排序以及优化
- js排序算法总结——冒泡,快速,选择,插入,希尔,归并
- [置顶] 十种排序算法总结(冒泡、插入、选择、希尔、归并、堆、快速,计数,桶,基数)
- 序算法总结——冒泡,快速,选择,插入,希尔,归并
- [置顶] js排序算法总结—冒泡,快速,选择,插入,希尔,归并
- 十种排序算法总结(冒泡、插入、选择、希尔、归并、堆、快速,计数,桶,基数)
- 【算法与数据结构】冒泡、插入、归并、堆排序、快速排序的Java实现代码
- js排序算法总结——冒泡,快速,选择,插入,希尔,归并(转载)
- 常见经典排序算法学习总结(插入、shell、冒泡、选择、归并、快排等)