- /**
- * 排序算法学习之希尔排序
- * 实现方法:
- * 希尔排序是特殊的插入排序
- * 插入排序按照处理的子数组长度递增分为多趟插入操作
- * 而每一趟插入操作处理的子数组元素索引间隔都是1(即步长)
- * 希尔排序每趟处理的子数组元素索引间隔是动态的。
- */
- package 排序算法.shellSort;
- public class ShellSort {
- /**
- * 对输入数组进行希尔排序
- * @param a 待排序数组,索引有效范围从0开始
- */
- @SuppressWarnings({ "rawtypes", "unchecked" })
- public static void shellSort(Comparable[] a) {
- int incr = a.length / 2;//初始步长
- while (incr >= 1) {
- for (int i = incr; i < a.length; i++) {
- Comparable insertElement = a[i];
- int j;
- for (j = i - incr; j >= 0 &&
- insertElement.compareTo(a[j]) < 0; j -= incr)
- a[j + incr] = a[j];
- a[j + incr] = insertElement;
- }
- if (incr == 2)
- incr = 1;
- else
- incr = (int) (incr / 2.2);
- }
- }
- }
- /**
- * 排序算法学习之选择排序
- * 实现方法:
- * 每次选择子数组中最大的元素依次排列在子数组末尾,
- * 子数组的长度依次递减。
- */
- package 排序算法.selectionSort;
- public class SelectionSort {
- @SuppressWarnings({ "rawtypes", "unchecked" })
- /**
- * 查找指定长度的数组中最大元素的索引
- * @param a 指定数组
- * @param n 数组长度
- * @return 最大元素的索引
- */
- public static int max(Comparable[] a, int n) {
- if (n < 0)
- throw new IllegalArgumentException("数组为空");
- int positionOfCurrentMax = 0;
- for (int i = 1; i <= n; i++)
- if (a[positionOfCurrentMax].compareTo(a[i]) < 0)
- positionOfCurrentMax = i;
- return positionOfCurrentMax;
- }
- /**
- * 交换指定数组中指定索引的元素
- * @param a 指定数组
- * @param i 第一个索引
- * @param j 第二个索引
- */
- public static void swap(Object[] a, int i, int j) {
- Object temp = a[i];
- a[i] = a[j];
- a[j] = temp;
- }
- /**
- * 对输入数组执行一般选择排序
- * @param a 输入数组
- */
- @SuppressWarnings("rawtypes")
- public void selectionSort(Comparable[] a) {
- //按照子数组长度递减的顺序进行每趟的选择操作
- for (int size = a.length; size > 1; size--) {
- int j = max(a, size - 1);
- swap(a, j, size - 1);
- }
- }
- /**
- * 对输入数组执行早结束版本的选择排序
- * @param a 输入数组,数组索引有效范围从0开始
- */
- @SuppressWarnings({ "rawtypes", "unchecked" })
- public void selectionSort2(Comparable[] a) {
- boolean sorted = false;//当前子数组是否有序的标志
- for (int size = a.length; !sorted && (size > 1); size--) {
- int pos = 0;
- sorted = true;
- for (int i = 1; i < size; i++)
- if (a[pos].compareTo(a[i]) <= 0)
- pos = i;
- else
- sorted = false;
- swap(a, pos, size - 1);
- }
- }
- }
- /**
- * 秩排序实现2
- * @author Sking
- */
- package 排序算法.rankSort;
- public class RankSort2 {
- /**
- * 对指定数组执行秩排序
- * @param a 待排序数组
- */
- @SuppressWarnings("rawtypes")
- private void rankSort2(Comparable[] a) {
- int[] r = new int[a.length];
- rank(a, r);//求数组元素的秩
- rearrange(a, r);//移动元素到索引为其秩的位置
- }
- /**
- * 交换指定数组中的两个元素
- * @param a 指定数组
- * @param i 第一个元素的索引值
- * @param j 第二个元素的索引值
- */
- @SuppressWarnings("rawtypes")
- private static void swap(Comparable[] a, int i, int j)
- {
- Comparable temp = a[i];
- a[i] = a[j];
- a[j] = temp;
- }
- /**
- * 交换秩数组中的两个元素
- * @param a 指定的秩数组
- * @param i 第一个元素的索引值
- * @param j 第二个元素的索引值
- */
- private static void swap(int[] a, int i, int j)//重载交换方法
- {
- int temp = a[i];
- a[i] = a[j];
- a[j] = temp;
- }
- /**
- * 根据秩数组对待排序数组进行排序
- * @param a 待排序数组
- * @param r 待排序数组的秩数组
- */
- @SuppressWarnings("rawtypes")
- private static void rearrange(Comparable[] a, int[] r) {
- for (int i = 0; i < a.length; i++)
- //依次检查位置i,如果有i=r[i]则表示元素i位置正确
- //否则交换位置i和位置r[i]上的元素(r[i]指出索引i位置
- //上的元素在排序数组中药位于r[i]的位置。
- while (r[i] != i) {
- int t = r[i];
- swap(a, i, t);
- swap(r, i, t);
- }
- }
- /**
- * 求指定数组元素的秩,存放在给定数组中
- * @param a 待排序数组
- * @param r 给定的存放元素秩的数组
- */
- @SuppressWarnings({ "rawtypes", "unchecked" })
- private static void rank(Comparable[] a, int[] r) {
- if (r.length < a.length)
- throw new IllegalArgumentException("秩数组长度异常!");
- for (int i = 0; i < a.length; i++)
- r[i] = 0;
- for (int i = 1; i < a.length; i++)
- for (int j = 0; j < i; j++)
- //当左边的元素小于等于右边的元素时,右边元素的秩加1
- if (a[j].compareTo(a[i]) <= 0)
- r[i]++;
- else
- //当左边的元素不小于右边的元素时,左边的元素的秩加1
- r[j]++;
- }
- }
- /**
- * 排序算法学习之秩排序
- *@author Sking
- 秩的定义: 一个序列中元素的秩被定义为序列中小于该元素的的元素
- 个数加上出现在其左边的相等元素的个数。则可知一个元素在排序序列
- 中的位置索引就是它们的秩。
- 实现方法:
- 1.计算待排序数组元素的秩
- 2.将数组元素移动到索引值为他们的秩的位置
- */
- package 排序算法.rankSort;
- public class RankSort1 {
- /**
- * 对指定数组执行秩排序
- * @param a 待排序的数组
- */
- @SuppressWarnings("rawtypes")
- public void rankSort(Comparable[] a) {
- int[] r = new int[a.length];
- rank(a, r);//求待排序数组元素的秩
- rearrange(a, r);//移动元素到索引为他们秩的位置,实现排序
- }
- /**
- * 使用数组元素的秩数组对数组进行排序
- * @param a 待排序数组
- * @param r 待排序数组元素的秩数组
- */
- @SuppressWarnings("rawtypes")
- private static void rearrange(Comparable[] a, int[] r) {
- Comparable[] u = new Comparable[a.length];
- for (int i = 0; i < a.length; i++)
- //移动元素到索引为他们秩的位置,实现排序
- u[r[i]] = a[i];
- for (int i = 0; i < a.length; i++)
- a[i] = u[i];
- }
- /**
- * 求指定数组元素的秩,存放在给定数组中
- * @param a 待排序数组
- * @param r 给定的存放元素秩的数组
- */
- @SuppressWarnings({ "rawtypes", "unchecked" })
- private static void rank(Comparable[] a, int[] r) {
- if (r.length < a.length)
- throw new IllegalArgumentException("秩数组长度异常!");
- for (int i = 0; i < a.length; i++)
- r[i] = 0;
- for (int i = 1; i < a.length; i++)
- for (int j = 0; j < i; j++)
- //当左边的元素小于等于右边的元素时,右边元素的秩加1
- if (a[j].compareTo(a[i]) <= 0)
- r[i]++;
- else
- //当左边的元素不小于右边的元素时,左边的元素的秩加1
- r[j]++;
- }
- }
- /**
- * 排序算法学习之快速排序的非递归实现,使用辅助栈
- * @author Sking
- */
- package 排序算法.quickSort;
- import 栈.ArrayStack;
- public class QuickSort2 {
- /**
- * 使用子数组的首个元素作为枢纽,划分子数组 划分后,
- * 枢纽左边的元素均小于枢纽,右边的元素均大于枢纽
- * 并返回划分的位置索引,是快速排序的核心方法
- *
- * @param a 待排序数组
- * @param p 子数组的开始索引
- * @param r 子数组的结束索引
- * @return 划分的索引位置
- */
- @SuppressWarnings({ })
- private int partition(int[] a, int p, int r) {
- int i = p, j = r + 1;
- int x = a[p];// 使用子数组的首个元素作为枢纽
- while (true) {
- // 从左边开始找到大于枢纽的元素索引
- while (a[++i] < x && i < r);
- // 同时从右边开始找到小于枢纽的元素索引
- while (a[--j]> x);
- if (i >= j)
- break;
- // 交换大于枢纽的元素到右边,小于枢纽的元素导左边
- swap(a, i, j);
- }// a[i]>=枢纽,a[j]<=枢纽,i>=j的时候表示已经划分完毕
- a[p] = a[j];// 交换枢纽索引位置所在元素和枢纽
- a[j] = x;
- return j;// j为枢纽索引
- }
- /**
- * 交换指定数组中的两个元素
- * @param a 指定数组
- * @param i 第一个元素的索引
- * @param j 第二个元素的索引
- */
- public static void swap(int[] a, int i, int j) {
- int temp = a[i];
- a[i] = a[j];
- a[j] = temp;
- }
- /**
- * 快速排序算法的非递归实现,使用辅助栈
- * @param a 待排序的数组段
- * @param p 数组段的左端索引
- * @param r 数组段的右端索引
- */
- @SuppressWarnings({ "unused" })
- private void qSort(int[] a, int p, int r) {
- ArrayStack stack = new ArrayStack();// 栈
- if (p < r) {
- int mid = partition(a, p, r);
- if (p < mid - 1) {
- stack.push(p);
- stack.push(mid - 1);
- }
- if (mid + 1 < r) {
- stack.push(mid + 1);
- stack.push(r);
- }
- while (!stack.empty()) {
- int m = (int) stack.pop();
- int n = (int) stack.pop();
- int l = partition(a, n, m);
- if (n < l - 1) {
- stack.push(n);
- stack.push(l - 1);
- }
- if (l + 1 < m) {
- stack.push(l + 1);
- stack.push(m);
- }
- }
- }
- }
- }
- /**
- * 排序算法学习之快速排序
- * @author Sking
- 实现方法:
- 通过把一个数组递归的划分为两个子数组。
- 递归的基本步骤:
- 1. 把数组划分成以一个元素为枢纽的左右两个子数组。
- 2. 调用自身的左边和右边以步骤1递归。
- 性能障碍:
- 对枢纽数据的选择是影响排序的效率。
- 性能:
- 最坏时间复杂度:O(n^2)
- 平均时间复杂度:O(n*log(n))
- 辅助空间:O(n)或O(log(n))
- 稳定性:不稳定
- 时间复杂度是O(n*log(n))
- */
- package 排序算法.quickSort;
- public class QuickSort {
- @SuppressWarnings("rawtypes")
- /**
- * 递归划分子数组a[p....r]
- * @param a 指定数组,索引有效范围从0开始
- * @param p 子数组的开始索引
- * @param r 子数组的结束索引
- */
- private void qSort(Comparable[] a,int p, int r) {
- if (p < r) {
- int q = partition(a,p, r);//划分的位置索引
- qSort(a,p, q - 1);//递归划分
- qSort(a,q + 1, r);
- }
- }
- /**
- * 使用子数组的首个元素作为枢纽,划分子数组
- * 划分后,枢纽左边的元素均小于枢纽,右边的元素均大于枢纽
- * 并返回划分的位置索引,是快速排序的核心方法
- * @param a 待排序数组
- * @param p 子数组的开始索引
- * @param r 子数组的结束索引
- * @return 划分的索引位置
- */
- @SuppressWarnings({ "rawtypes", "unchecked" })
- private int partition(Comparable[] a,int p, int r) {
- int i = p, j = r + 1;
- Comparable x = a[p];//使用子数组的首个元素作为枢纽
- while (true) {
- //从左边开始找到大于枢纽的元素索引
- while (a[++i].compareTo(x) < 0 && i < r);
- //同时从右边开始找到小于枢纽的元素索引
- while (a[--j].compareTo(x) > 0);
- if (i >= j)
- break;
- //交换大于枢纽的元素到右边,小于枢纽的元素导左边
- swap(a,i, j);
- }//a[i]>=枢纽,a[j]<=枢纽,i>=j的时候表示已经划分完毕
- a[p] = a[j];//交换枢纽索引位置所在元素和枢纽
- a[j] = x;
- return j;//j为枢纽索引
- }
- /**
- * 交换指定数组中的两个元素
- * @param a 指定数组
- * @param i 第一个元素的索引
- * @param j 第二个元素的索引
- */
- @SuppressWarnings("rawtypes")
- public static void swap(Comparable[] a,int i, int j) {
- Comparable temp = a[i];
- a[i] = a[j];
- a[j] = temp;
- }
- }
- /**
- * 排序算法学习之一般合并排序
- * @author Sking
- 实现方法:
- 将待排序数组分为大小大致相等的2个子数组
- 分别对两个子数组进行排序,如此递归划分排序
- 最后将排序号的子数组再递归合并为更大的已排序数组
- 直到整个数组已排序为止。
- */
- package 排序算法.mergeSort;
- public class MergeSort2 {
- /**
- * 对指定数组的指定范围执行一般合并排序
- *
- * @param a
- * 指定数组
- * @param left
- * 指定范围的左边索引
- * @param right
- * 指定范围的右边索引
- */
- @SuppressWarnings("rawtypes")
- public void mergeSort2(Comparable[] a, int left, int right) {
- Comparable[] b = new Comparable[a.length];
- if (left < right) {
- int i = (left + right) / 2;
- mergeSort2(a, left, i);//左子段递归排序
- mergeSort2(a, i + 1, right);//右子段递归排序
- merge(a, b, left, i, right);//合并子段到新数组中
- copy(a, b, left, right);//复制排序后的元素到原数组
- }
- }
- /**
- * 合并已排序子数组c[l...m]和c[m+1,r]到新数组中,新数组保持有序
- *
- * @param c存放两个已排序数组的数组
- * @param d
- * 新数组,用于存放合并后的数组
- * @param l
- * 左边子数组的起始索引
- * @param m
- * 左边子数组的结束索引
- * @param r
- * 右边子数组的结束索引
- */
- @SuppressWarnings({ "rawtypes", "unchecked" })
- private static void merge(Comparable[] c, Comparable[] d, int l, int m,
- int r) {
- int i = l;
- int j = m + 1;
- int k = l;
- while ((i <= m) && (j <= r))
- if (c[i].compareTo(c[j]) <= 0)
- d[k++] = c[i++];
- else
- d[k++] = c[j++];
- if (i > m)
- for (int q = j; q <= r; q++)
- d[k++] = c[q];
- else
- for (int q = i; q <= m; q++)
- d[k++] = c[q];
- }
- /**
- * 复制源数组中指定索引范围内的元素到目标数组
- *
- * @param a
- * 源数组
- * @param b
- * 目标数组
- * @param left
- * 指定范围的左边索引
- * @param right
- * 指定范围的右边索引
- */
- @SuppressWarnings("rawtypes")
- private static void copy(Comparable[] a, Comparable[] b, int left, int
- right) {
- int i = left;
- int j = left;
- while (i <= right)
- a[i++] = b[j++];
- }
- }
- /**
- * 排序算法学习之合并排序
- * @author Sking
- 实现方法:
- 将待排序数组中相邻元素两两配对作为子数组,排序各个子数组,
- 构成n/2组长度为2的排序好的子数组;然后将长度为2的子排序
- 子数组再两两配对,并排序,构成长度为4的已排序子数组。如此递归
- 直到整个数组是已排序为止。
- 最坏时间复杂度:O(n*log(n))
- 平均时间复杂度:O(n*log(n))
- 辅助空间:O(n)
- 稳定性:稳定
- */
- package 排序算法.mergeSort;
- public class MergeSort {
- @SuppressWarnings("rawtypes")
- /**
- * 对输入数组执行合并排序
- * @param a 指定数组,索引有效位置从0开始
- */
- public void mergeSort(Comparable[] a) {
- Comparable[] b = new Comparable[a.length];// 辅助空间
- int s = 1;// 初始子数组长度设置为1
- while (s < a.length) {
- mergePass(a, b, s);
- s += s;
- mergePass(b, a, s);
- s += s;
- }
- }
- /**
- * 合并相邻的已排序子数组为更大的已排序子数组
- *
- * @param x
- * 包含了已排序子数组的数组
- * @param y
- * 包含更大的已排序子数组的数组
- * @param s
- * 已排序子数组的长度
- */
- @SuppressWarnings("rawtypes")
- public static void mergePass(Comparable[] x, Comparable[] y, int s) {
- int i = 0;
- while (i <= x.length - 2 * s) {// 合并两相邻的长度为s的已排序子数组
- merge(x, y, i, i + s - 1, i + 2 * s - 1);
- i = i + 2 * s;
- }// 当i>x.length-2*s的时候退出while循环
- // 处理剩下的部分,可以是s长度的已排序数组+“零片”
- // 也可能只是“零片“,此时不需要合并。
- if (i + s < x.length) {
- // 合并相邻的长度s的已排序子数组和长度小于s的“零片”
- merge(x, y, i, i + s - 1, x.length - 1);
- } else
- // 处理”零片“
- for (int j = i; j < x.length; j++)
- y[j] = x[j];
- }
- /**
- * 合并已排序子数组c[l...m]和c[m+1,r]到新数组中,新数组保持有序
- *
- * @param c存放两个已排序数组的数组
- * @param d
- * 新数组,用于存放合并后的数组
- * @param l
- * 左边子数组的起始索引
- * @param m
- * 左边子数组的结束索引
- * @param r
- * 右边子数组的结束索引
- */
- @SuppressWarnings({ "unchecked", "rawtypes" })
- static void merge(Comparable[] c, Comparable[] d, int l, int m, int r) {
- int i = l;// 第一个子数组的索引指针
- int j = m + 1;// 第二个子数组的索引指针
- int k = l;// 新数组的索引指针
- while ((i <= m) && (j <= r))
- if (c[i].compareTo(c[j]) <= 0)
- d[k++] = c[i++];
- else
- d[k++] = c[j++];
- if (i > m)// 将右边子数组剩下的元素添加到新数组中
- for (int q = j; q <= r; q++)
- d[k++] = c[q];
- else
- // 将左边子数组剩下的元素添加到新数组中
- for (int q = i; q <= m; q++)
- d[k++] = c[q];
- }
- }
- /**
- * 排序算法学习之插入排序
- * @author Sking
- */
- package 排序算法.insertionSort;
- public class InsertionSort {
- @SuppressWarnings({ "rawtypes", "unchecked" })
- /**
- * 一次元素插入的实现,在n长度的子数组中插入元素x到合适位置
- * @param a 带排序数组,索引有效范围从0开始
- * @param n 子数组元素个数
- * @param x 待插入的元素
- */
- public static void insert(Comparable[] a, int n, Comparable x) {
- if (a.length < n + 1)//数组已满,不可插入
- throw new IllegalArgumentException("数组不够大");
- int i;//当前被比较元素索引
- for (i = n - 1; i >= 0 && x.compareTo(a[i]) < 0; i--)
- a[i + 1] = a[i];//比x大的元素后移,寻找x插入的位置
- a[i + 1] = x;//插入x
- }
- /**
- * 对输入数组执行插入排序
- * @param a 待排序数组,索引有效位置从0开始
- */
- @SuppressWarnings("rawtypes")
- public static void insertionSort(Comparable[] a) {
- //i表示一次元素插入步骤所考虑的子数组长度,大小递增
- for (int i = 1; i < a.length; i++)
- insert(a, i, a[i]);
- }
- }
- /**
- * 排序算法学习之冒泡排序
- * 使用时,将Comparable类型替换为指定类型,必要时,要定义比较方法
- * @author Sking
- */
- package 排序算法.bubbleSort;
- public class BubbleSort {
- /**
- * 交换数组元素方法
- * @param a 指定数组
- * @param i 第一个索引
- * @param j 第二个索引
- */
- @SuppressWarnings("rawtypes")
- public static void swap(Comparable[] a, int i, int j) {
- Comparable t = a[i];
- a[i] = a[j];
- a[j] = t;
- }
- /**
- * 一次冒泡迭代,分别比较相邻元素选择单趟的最大元素
- * @param a 指定数组
- * @param n 冒泡子序列的长度
- */
- @SuppressWarnings({ "rawtypes", "unchecked" })
- private static void bubble(Comparable[] a, int n) {
- for (int i = 0; i < n - 1; i++)
- if (a[i].compareTo(a[i + 1]) > 0)
- swap(a, i, i + 1);
- }
- /**
- * 一般冒泡排序
- * @param a 指定数组
- */
- @SuppressWarnings("rawtypes")
- public static void bubbleSort(Comparable[] a) {
- for (int i = a.length; i > 1; i--)
- bubble(a, i);
- }
- /**
- * 早结束版本的冒泡排序方法的一次迭代
- * @param a 指定数组
- * @param n 冒泡子序列的长度
- * @return 如果该次迭代中进行了元素交换位置,则返回true,否则返回false
- */
- @SuppressWarnings({ "rawtypes", "unchecked" })
- private static boolean haveBubble(Comparable[] a,int n){
- boolean swapped=false;//标志一次冒泡是否进行交换
- for(int i=0;i<n-1;i++)
- if(a[i].compareTo(a[i+1])>0){
- swap(a,i,i+1);
- swapped=true;
- }
- return swapped;
- }
- /**
- * 早结束版本的冒泡排序
- * @param a 指定排序的数组
- */
- @SuppressWarnings("rawtypes")
- public static void bubbleSort2(Comparable[] a){
- for(int i=a.length;i>1&&haveBubble(a,i);i--);
- }
- }