15、排序:选择类排序和归并排序

  代码更新自上篇,如下:

  1 package ren.laughing.datastructure.algorithm;
  2
  3 import ren.laughing.datastructure.baseImpl.BinTreeNode;
  4
  5 /**
  6  * 排序
  7  *
  8  * @author Laughing_Lz
  9  * @time 2016年4月22日
 10  */
 11 public class Sorter {
 12     /**
 13      * 直接插入排序(从小到大) 时间复杂度为O(n^2)
 14      *
 15      * @param arr
 16      *            要排序的数组
 17      * @param low
 18      *            要排序的最低下标
 19      * @param high
 20      *            要排序的最高下标
 21      * @return 排序后的数组
 22      */
 23     public static void insertSort(int[] arr, int low, int high) {
 24         for (int i = low + 1; i <= high; i++) {
 25             int temp = arr[i];// 待插入元素
 26             int j = i;// 记录待插入位置
 27             for (; j > low && temp < arr[j - 1]; j--) {//
 28                 arr[j] = arr[j - 1];// 后移
 29             }
 30             arr[j] = temp;// 插入
 31         }
 32         printResult("直接插入排序:", arr);
 33     }
 34
 35     /**
 36      * 折半插入排序 时间复杂度仍为O(n^2)
 37      *
 38      * @param arr
 39      * @param low
 40      * @param high
 41      * @return
 42      */
 43     public static void binInsertSort(int[] arr, int low, int high) {
 44         for (int i = low + 1; i <= high; i++) {
 45             int temp = arr[i];
 46             int lo = low;
 47             int hi = i - 1;
 48             while (lo <= hi) {// 注意‘=‘ ★
 49                 int mid = (lo + hi) / 2;
 50                 if (temp < arr[mid]) {
 51                     hi = mid - 1;// 由此看出最终temp的位置在hi+1
 52                 } else {
 53                     lo = mid + 1;// hi+1等同于lo (此处应该没错吧?)
 54                 }
 55             }
 56             for (int j = i - 1; j > hi; j--) {// 后移
 57                 arr[j + 1] = arr[j];
 58             }
 59             arr[hi + 1] = temp;// 插入
 60         }
 61         printResult("折半插入排序:", arr);
 62     }
 63
 64     /**
 65      * 希尔排序(缩小增量排序) 当n在某个范围内,时间复杂度可达到O(n^1.3)
 66      *
 67      * @param arr
 68      * @param low
 69      * @param high
 70      * @param delta
 71      *            步长序列
 72      */
 73     public static void shellSort(int[] arr, int low, int high, int[] delta) {
 74         for (int i = 0; i < delta.length; i++) {// 第一步:遍历步长序列
 75             for (int m = low; m < low + delta[i]; m++) {// 第二步:循环起始点,保证每个被拆分的子序列都被直接排序
 76                 for (int j = m + delta[i]; j <= high; j += delta[i]) {// 对每个子序列直接排序
 77                     int temp = arr[j];
 78                     int k = j;
 79                     for (; k > m && temp < arr[(k - delta[i])]; k -= delta[i]) {
 80                         arr[k] = arr[(k - delta[i])];// 后移
 81                     }
 82                     arr[k] = temp;// 插入
 83                 }
 84             }
 85         }
 86         printResult("希尔排序:", arr);
 87     }
 88
 89     /**
 90      * 冒泡排序 时间复杂度为O(n^2)
 91      *
 92      * @param arr
 93      * @param low
 94      * @param high
 95      */
 96     public static void bubbleSort(int[] arr, int low, int high) {
 97         int len = high - low + 1;
 98         for (int i = 1; i < len; i++) {
 99             for (int j = low; j <= high - i; j++) {// 这里j<= high-i ★
100                 if (arr[j] > arr[j + 1]) {
101                     int temp = arr[j];// 交换
102                     arr[j] = arr[j + 1];
103                     arr[j + 1] = temp;
104                 }
105             }
106         }
107         printResult("冒泡排序:", arr);
108     }
109
110     /**
111      * 快速排序 需要递归
112      *
113      * @param arr
114      * @param low
115      * @param high
116      */
117     public static void quickSort(int[] arr, int low, int high) {
118         if (low < high) {
119             int pa = partition(arr, low, high);// 分治
120             quickSort(arr, low, pa - 1);
121             quickSort(arr, pa + 1, high);
122         }
123     }
124
125     /**
126      * 将序列划分为两个子序列并返回枢轴元素的位置
127      *
128      * @param arr
129      * @param low
130      *            划分区间
131      * @param high
132      * @return
133      */
134     private static int partition(int[] arr, int low, int high) {
135         int pivot = arr[low];// 首先定义枢轴为low所指元素
136         while (low < high) {// 交替扫描
137             while (arr[high] > pivot && low < high) {
138                 high--;
139             }
140             arr[low] = arr[high];// 将比 pivot 小的元素移向低端
141             while (arr[low] < pivot && low < high) {
142                 low++;
143             }
144             arr[high] = arr[low];// 将比 pivot 大的元素移向高端
145         }
146         arr[low] = pivot;// 设置枢轴
147         return low;
148     }
149
150     /**
151      * 简单选择排序 时间复杂度为O(n^2)
152      *
153      * @param arr
154      * @param low
155      * @param high
156      */
157     public static void selectSort(int[] arr, int low, int high) {
158         for (int i = low; i < high - 1; i++) {
159             int min = i;// 记录位置,不是元素是位置!★
160             for (int j = i; j <= high; j++) {
161                 if (arr[j] < arr[min]) {
162                     min = j;// 更新最小元素位置
163                 }
164             }
165             if (min != i) {// 交换
166                 int temp = arr[min];
167                 arr[min] = arr[i];
168                 arr[i] = temp;
169             }
170         }
171         printResult("简单选择排序:", arr);
172     }
173
174     /**
175      * 堆排序,时间复杂度为O(nlogn) 堆排序中,arr[]数组的首位arr[0]弃用。所以这里arr[1]为根结点
176      *
177      * @param arr
178      */
179     public static void heapSelectSort(int[] arr) {
180         int n = arr.length - 1;
181         for (int i = n / 2; i >= 1; i--) {// 遍历叶子结点的上层第一个结点及之前所有结点,i>=1是因为数组中首位元素弃用
182             heapAdjust(arr, i, n);// 初始化建堆,i=n/2位置
183         }
184         for (int i = n; i > 1; i--) {//
185             int temp = arr[1];// 堆顶元素(根节点)为最大元素,将它和堆底元素交换
186             arr[1] = arr[i];
187             arr[i] = temp;
188             heapAdjust(arr, 1, i - 1);// 从根结点更新堆
189         }
190         printResult("堆排序:", arr);
191     }
192
193     /**
194      * 创建堆
195      *
196      * @param r
197      *            数组元素根据二叉树层次遍历顺序存储
198      * @param low
199      *            遍历是否比左右孩子大的起始结点
200      * @param high
201      *            数组长度
202      */
203     private static void heapAdjust(int[] r, int low, int high) {
204         int temp = r[low];// r[low]为要与左右孩子比较的父结点,以保证其比左右孩子都大
205         for (int j = 2 * low; j <= high; j = j * 2) {// 需要循环保证该起始结点low以下的树都符合堆定义★
206             if (j < high && r[j] < r[j + 1]) {// r[j]是r[low]的左孩子,r[j+1]是右孩子
207                 j++;
208             }
209             if (temp > r[j]) {// 父结点与较大的孩子比较大小,若父结点小,交换
210                 break;
211             }
212             r[low] = r[j];// 父结点存放的是三者中最大的元素
213             low = j;
214         }
215         r[low] = temp;// 将原父结点的元素存入孩子结点
216     }
217
218     /**
219      * 归并排序
220      *
221      * @param arr
222      * @param low
223      * @param high
224      */
225     public static void mergeSort(int[] arr, int low, int high) {
226         if (low < high) {// 分治
227             mergeSort(arr, low, (low + high) / 2);
228             mergeSort(arr, (low + high) / 2 + 1, high);
229             merge(arr, low, (low + high) / 2, high);
230         }
231     }
232
233     /**
234      * 将两个有序区间[low,mid]和[mid+1,high]合并成一个有序区间
235      *
236      * @param arr
237      * @param low
238      * @param mid
239      * @param high
240      */
241     private static void merge(int[] arr, int low, int mid, int high) {
242         int[] temp = new int[high - low + 1];
243         int a = low;
244         int b = mid + 1;
245         int t = 0;
246         while (a <= mid && b <= high) {// 注意这个循环★
247             if (arr[a] < arr[b]) {
248                 temp[t++] = arr[a++];
249             } else {
250                 temp[t++] = arr[b++];
251             }
252         }
253         while (a <= mid) {
254             temp[t++] = arr[a++];
255         }
256         while (b <= high) {
257             temp[t++] = arr[b++];
258         }
259         for (int i = 0; i < temp.length; i++) {
260             arr[low + i] = temp[i];
261         }
262     }
263
264     /**
265      * 程序入口
266      *
267      * @param args
268      */
269     public static void main(String[] args) {
270         int[] arr = new int[] { 2, 5, 7, 3, 4, 8, 1, 9, 6, 0 };
271         int[] delta = new int[] { 5, 3, 1 };
272         // insertSort(arr, 0, 9);
273         // binInsertSort(arr, 0, 9);
274         // shellSort(arr, 0, 9, delta);
275         // bubbleSort(arr, 0, 9);
276         // quickSort(arr, 0, 9);
277         // printResult("快速排序:", arr);
278         // selectSort(arr, 0, 9);
279         // heapSelectSort(arr);
280         mergeSort(arr, 0, 9);
281         printResult("归并排序:", arr);
282     }
283
284     /**
285      * 打印
286      *
287      * @param str
288      * @param arr
289      */
290     public static void printResult(String str, int[] arr) {
291         System.out.print(str);
292         for (int i = 0; i < arr.length; i++) {
293             System.out.print(arr[i] + " ");
294         }
295         System.out.println();
296     }
297 }
时间: 2024-11-06 10:11:52

15、排序:选择类排序和归并排序的相关文章

详谈排序算法之选择类排序(两种方法实现堆排序)

   今天我们再来讨论一下选择类排序,选择类排序分为:简单排序,树形选择排序和堆排序.但我们主要说的是简单和堆排序两个,因为树形选择排序使用了较多的辅助空间,以及和∞进行多余比较,为弥补树型选择排序的这些缺点, J.W.J.Williams 在 1964 年提出了进一步的改进方法,即堆排序.对于我个人而言..一开始并不是很理解它的算法思想,纠结了许久.在网上查找资料的时候发现这位大神的文章思路十分清晰,而且把创建堆以及堆化数组的算法讲解的十分详细.如果有不明白堆排序思路的,可以先看看这篇文章~堆

选择类排序总结

选择类排序总结 所谓选择类排序的思想就是:从数组的中选出最大或最小的,通过多次选择最后达到排序的目的 首先是简单选择排序 思想:每趟扫描中,选出最小的数字放在最前面,然后从第二个数字开始扫描,直到只剩下最后一个数不需要扫描 void EasySelect_Sort(int a[],int n) { int k; for(int i=1;i<n;i++) { k=i-1; for(int j=i;j<n;j++) { if(a[j]<a[k]) { k=j; } } if(k!=(i-1)

选择类排序

#include<stdio.h> /* *选择类排序,每天一道算法题 *按照从小到大的顺序进行排序 * */ //遍历序列 void traverseArray(int *p,int length) { int i=0; for(;i<length;i++) { printf("%d\n",p[i]); } } //简单选择类排序 void selectSort(int *p,int length) { int i,j,temp,index; for(i=0;i&l

选择类排序:选择排序,堆排序

选择类排序:1:简单选择排序O(n^2),空间O(1) 2:堆排序O(n乘以log以2为底,n的对数),空间复杂度O(1) //选择排序 void SelectSort(int R[],int n) { int i,j,k; int tmp; for(i=0;i<n-1;i++) { k=i; for(j=i+1;j<n;j++) { if(R[j]<R[k]) k=j; } if(k!=i) { tmp=R[i]; R[i]=R[k]; R[k]=tmp; } } } //堆排序 vo

八大排序之选择类排序

直接插入排序 在有序数组中插入一个元素,可以作为一种排序方法的基础 只有一个元素的数组是一个有序数组,对n个元素的数组,可以从第一个元素所构成的单元数组开始,不断实施插入操作 插入第二个元素,得到2个元素的有序数组.插入第三个元素,得到3个元素的有序数组 如此反复,得到n个元素的有序数组 示例 对序列:6,5,8,4,3,1 进行直接插入排序 图中灰色部分代表待排序列 图中透明部分代表已排序列 int main() { int a[10] = { 6,5,8,4,3,7 }; int temp,

常见的五类排序算法图解和实现(多关键字排序:基数排序以及各个排序算法的总结)

基数排序思想 完全不同于以前的排序算法,可以说,基数排序也叫做多关键字排序,基数排序是一种借助“多关键字排序”的思想来实现“单关键字排序”的内部排序算法. 两种方式: 1.最高位优先,先按照最高位排成若干子序列,再对子序列按照次高位排序 2.最低位优先:不必分子序列,每次排序全体元素都参与,不比较,而是通过分配+收集的方式. 多关键字排序 例:将下表所示的学生成绩单按数学成绩的等级由高到低排序,数学成绩相同的学生再按英语成绩的高低等级排序.        第一个关键字是数学成绩,第二个关键字是英

排序算法的C语言实现(上 比较类排序:插入排序、快速排序与归并排序)

总述:排序是指将元素集合按规定的顺序排列.通常有两种排序方法:升序排列和降序排列.例如,如整数集{6,8,9,5}进行升序排列,结果为{5,6,8,9},对其进行降序排列结果为{9,8,6,5}.虽然排序的显著目的是排列数据以显示它,但它往往可以用来解决其他的问题,特别是作为某些成型算法的一部分. 总的来说,排序算法分为两大类:比较排序 和 线性时间排序. 比较排序依赖于比较和交换来将元素移动到正确的位置上.它们的运行时间往往不可能小于O(nlgn). 对于线性时间排序,它的运行时间往往与它处理

插入排序、冒泡排序、选择排序、希尔排序、快速排序、归并排序、堆排序和LST基数排序——C++实现

首先是算法实现文件Sort.h,代码如下: /* * 实现了八个常用的排序算法:插入排序.冒泡排序.选择排序.希尔排序 * 以及快速排序.归并排序.堆排序和LST基数排序 * @author gkh178 */ #include <iostream> template<class T> void swap_value(T &a, T &b) { T temp = a; a = b; b = temp; } //插入排序:时间复杂度o(n^2) template<

九种经典排序算法详解(冒泡排序,插入排序,选择排序,快速排序,归并排序,堆排序,计数排序,桶排序,基数排序)

综述 最近复习了各种排序算法,记录了一下学习总结和心得,希望对大家能有所帮助.本文介绍了冒泡排序.插入排序.选择排序.快速排序.归并排序.堆排序.计数排序.桶排序.基数排序9种经典的排序算法.针对每种排序算法分析了算法的主要思路,每个算法都附上了伪代码和C++实现. 算法分类 原地排序(in-place):没有使用辅助数据结构来存储中间结果的排序**算法. 非原地排序(not-in-place / out-of-place):使用了辅助数据结构来存储中间结果的排序算法 稳定排序:数列值(key)