排序法 |
最差时间分析 | 平均时间复杂度 | 稳定度 | 空间复杂度 |
冒泡排序 | O(n2) | O(n2) | 稳定 | O(1) |
快速排序 | O(n2) | O(n*log2n) | 不稳定 | O(log2n)~O(n) |
选择排序 | O(n2) | O(n2) | 不稳定 | O(1) |
二叉树排序 | O(n2) | O(n*log2n) | 稳定 | O(n) |
插入排序 |
O(n2) | O(n2) | 稳定 | O(1) |
堆排序 | O(n*log2n) | O(n*log2n) | 不稳定 | O(1) |
希尔排序 | O | O | 不稳定 | O(1) |
折半查找(非递归)
/** * 折半查找算法(非递归形式) * * @param array * @param key * @return */ public static int Bsearch(int array[], int key) { int mid; int low = 0; int high = array.length - 1; while (low <= high) { mid = (low + high) / 2; if (key == array[mid]) return mid; else if (key < array[mid]) high = mid - 1; else low = mid + 1; } return -1; }
/** * 折半查找算法(递归形式) * @param array * @param low * @param high * @param key * @return */ public static int BsearchRec(int array[], int low, int high, int key) { int mid; if (low <= high) { mid = (low + high) / 2; if (key == array[mid]) return mid; else if (key < array[mid]) return BsearchRec(array, low, mid - 1, key); else return BsearchRec(array, mid + 1, high, key); } return -1; }
直接插入排序
一般来说,插入排序都采用in-place在数组上实现。具体算法描述如下:(wiki)
/** * 直接插入排序 * * @param array * @return */ public static int[] InsertSort(int array[]) { int n = array.length; int i, j; for (i = 0; i < n; i++) {// 对所有的元素都进行插入操作:n个元素 int temp = array[i]; for (j = i; j > 0 && temp < array[j - 1]; j--) { // 将该元素和它前面所有的元素比较,并将小于它的元素往后移 array[j] = array[j - 1]; } array[j] = temp;// 将最后一个小于它的元素覆盖 } return array; }
public void insertSort(int a[]) { int n = a.length; int temp; int j; for (int i = 1; i < n; i++) { temp = a[i]; for (j = i - 1; j >= 0 && temp < a[j]; j--) { a[j + 1] = a[j]; } a[j + 1] = temp; } for (int i = 0; i < a.length; i++) { System.out.print(a[i] + " "); } }
冒泡排序
重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
冒泡排序算法的运作如下:
/** * 冒泡排序 * * @param array * @return */ public static int[] BubbleSort(int array[]) { boolean flag = true; int n = array.length; int temp = 0; for (int i = 0; i < n - 1; i++) {// 冒泡排序的轮数:n-1次,每一轮都将该轮中最大的元素放在末尾 flag = true; for (int j = 0; j < n - i - 1; j++) {// 具体的一轮:j与j+1进行比较和交换,j的最大值是n-i-1 if (array[j] > array[j + 1]) { temp = array[j]; array[j] = array[j + 1]; array[j + 1] = temp; flag = false; }// 如果前面的元素都是有序,则该轮for循环结束后flag都是true,直接退出 } if (flag == true) break; } return array; }
冒泡算法2,从小到大排序, 从左到右,更符合冒泡思想,小的数字向上
/** * 冒泡算法2,从小到大排序, 从左到右,更符合冒泡思想,小的数字向上排 * * @param array * @return */ public static int[] BubbleSort2(int array[]) { boolean flag = true;// 标志位,当满足顺序时,如果i仍然没有遍历到倒数第二个元素则可以直接退出。 int n = array.length; int temp = 0; for (int i = 0; i < n - 1; i++) {// n-1轮(最后一轮只剩下一个不用排) flag = true; for (int j = n - 1; j > i; j--) {// 将最小的一个数放在通过冒泡,放置到第i个位置 if (array[j] < array[j - 1]) { temp = array[j - 1]; array[j - 1] = array[j]; array[j] = temp; flag = false; } } if (flag == true) break; for (int k = 0; k < array.length; k++) { System.out.print(array[k] + " "); } System.out.println(""); } return array; }
简单选择排序
它的工作原理如下。首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到排序序列末尾。以此类推,直到所有元素均排序完毕。
/** * 简单选择排序 * * @param array * @return */ public static int[] SelectSort(int array[]) { int n = array.length; int i, j, min, temp; for (i = 0; i < n - 1; i++) {// n-1次最小数的选择,因为最后一个肯定是最后一轮中最小的的,所以不用比较 min = i; for (j = i + 1; j < n; j++) // 从当前元素后面的元素中选择一个最小的和当前元素交换 if (array[j] < array[min]) min = j; temp = array[i]; array[i] = array[min]; array[min] = temp; } return array; }
快速排序
快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为两个子序列(sub-lists)。
步骤为:
递回的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递回下去,但是这个算法总会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
/** * 快速排序算法 * * 一趟快速排序的过程 1)设置两个变量I、J,排序开始的时候:I=0,J=N-1; * 2)以第一个数组元素作为关键数据,赋值给key,即key=A[0]; * 3)从J开始向前搜索,即由后开始向前搜索(J=J-1),找到第一个小于key的值A[J],停下来进入4; * 4)从I开始向后搜索,即由前开始向后搜索(I=I+1),找到第一个大于key的A[I],将A[I]与A[J]交换; 5)重复第3、4步,直到 * I=J; (3,4步是在程序中没找到时候j=j-1,i=i+1,直至找到为止。 找到并交换的时候i, * j指针位置不变。另外当i=j这过程一定正好是i+或j-完成的最后另循环结束。) * * @param array * @param low * @param high */ public void QuickSort(int array[], int low, int high) { int pivotkey, i, j; if (low < high) { pivotkey = array[low]; i = low; j = high; while (i < j) { while (i < j && array[j] >= pivotkey) j--; if (i < j) array[i++] = array[j]; while (i < j && array[i] <= pivotkey) i++; if (i < j) array[j--] = array[i]; } array[i] = pivotkey; QuickSort(array, low, i - 1); QuickSort(array, i + 1, high); } }
归并排序
/** * 归并排序:对两个已经有序的数组进行排序的算法 * * @param arrayA * @param arrayB * @return */ public static int[] MergeSort(int[] arrayA, int[] arrayB) { int[] arrayC = new int[arrayA.length + arrayB.length]; int k = 0; int i = 0; int j = 0; while (i < arrayA.length && j < arrayB.length) { if (arrayA[i] < arrayB[j]) arrayC[k++] = arrayA[i++]; else arrayC[k++] = arrayB[j++]; } while (i < arrayA.length) arrayC[k++] = arrayA[i++]; while (j < arrayB.length) arrayC[k++] = arrayB[j++]; return arrayC; }
希尔排序
算法基本思想:
先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组,所有距离为d1倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后第二个增量d2<d1重复上诉的分组和排序,直到取值为 dt = 1,即所有记录放在同一个组中进行直接插入排序。
public void shellSort(int a[]) { int n = a.length; int d = n / 2; int temp; int i; int j; int k; while (d != 0) { for (i = 0; i < d; i++) { for (j = i + d; j < n; j = j + d) { temp = a[j]; for (k = j - d; k >= 0 && temp < a[k]; k = k - d) { a[k + d] = a[k]; } a[k + d] = temp; } } d = d / 2; } }
public class ShellSort { public static int[] a = { 10, 32, 1, 9, 5, 7, 12, 0, 4, 3 }; public static void main(String args[]) { int i; // 循环计数变量 int Index = a.length;// 数据索引变量 System.out.print("排序前: "); for (i = 0; i < Index - 1; i++) System.out.printf("%3s ", a[i]); System.out.println(""); shellSort(Index - 1); // 选择排序 // 排序后结果 System.out.print("排序后: "); for (i = 0; i < Index - 1; i++) System.out.printf("%3s ", a[i]); System.out.println(""); } public static void shellSort(int Index) { int j, k; // 循环计数变量 int Temp; // 暂存变量 boolean Change; // 数据是否改变 int DataLength; // 分割集合的间隔长度 int Pointer; // 进行处理的位置 DataLength = (int) Index / 2; // 初始集合间隔长度 while (DataLength != 0) // 数列仍可进行分割 { // 对各个集合进行处理 for (j = DataLength; j < Index; j++) { Change = false; Temp = a[j]; // 暂存Data[j]的值,待交换值时用 Pointer = j - DataLength; // 计算进行处理的位置 // 进行集合内数值的比较与交换值 while (Temp < a[Pointer] && Pointer >= 0 && Pointer <= Index) { a[Pointer + DataLength] = a[Pointer]; // 计算下一个欲进行处理的位置 Pointer = Pointer - DataLength; Change = true; if (Pointer < 0 || Pointer > Index) break; } // 与最后的数值交换 a[Pointer + DataLength] = Temp; if (Change) { // 打印目前排序结果 System.out.print("排序中: "); for (k = 0; k < Index; k++) System.out.printf("%3s ", a[k]); System.out.println(""); } } DataLength = DataLength / 2; // 计算下次分割的间隔长度 } } }
最大公约数,辗转相除法
public static int gcd(int x, int y) { if (y == 0) return x; else return gcd(y, x % y); }
/** * 最大公约数函数 * * @param num1 * @param num2 * @return */ public static int gcd(int num1, int num2) { int r = 0; while (num2 != 0) { r = num1 % num2; num1 = num2; num2 = r; } return num1; }
减法~
// 传入的x大于y public static int gcd(int x, int y) { if (x < y) return gcd(y, x); if (y == 0) return x; else return gcd(x - y, y); }
寻找数组中重复次数的最多的那个数(数组有上限)
/** * * @param array * 待寻找重复数的数组 * @param num * 预设不同数的个数(有上限的情况下) */ public static int FindRepeatest(int array[], int num) { // 存放每个数的重复次数(重复度) int[] assistArray = new int[num]; // 当前个数最多的那个数 int max = 0; for (int i = 0; i < array.length; i++) { assistArray[array[i]]++; if (assistArray[array[i]] > assistArray[max]) max = array[i]; } return max; }
斐波那契序列
public class Fibonacci { public int F(int n) { if (n <= 0) return 0; else if (n == 1) return 1; else return F(n - 1) + F(n - 2); } }
public class Fibonacci2 { public int F2(int a, int b, int n) { if (n == 1) return a; else if (n == 2) return b; else return F2(a, b, n - 1) + F2(a, b, n - 2); } }
汉诺塔问题:
public class Hanoi { private int c = 0; public void hanoi(int n, char x, char y, char z) { if (n == 1) { move(x, 1, z); } else { hanoi(n - 1, x, z, y); move(x, n, z); hanoi(n - 1, y, x, z); } } public void move(char x, int n, char z) { System.out.println(++c + ".移动" + n + "从" + x + "到" + z); } public static void main(String[] args) { Hanoi hanoi = new Hanoi(); hanoi.hanoi(3, 'x', 'y', 'z'); } }