排序法 | 最差时间分析 | 平均时间复杂度 | 稳定度 | 空间复杂度 |
冒泡排序 | 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)
- 从第一个元素开始,该元素可以认为已经被排序
- 取出下一个元素,在已经排序的元素序列中从后向前扫描
- 如果该元素(已排序)大于新元素,将该元素移到下一位置
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
- 将新元素插入到该位置中
- 重复步骤2~5
/**
* 直接插入排序
*
* @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)。
步骤为:
- 从数列中挑出一个元素,称为 "基准"(pivot),
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分割结束之后,该基准就处于数列的中间位置。这个称为分割(partition)操作。
- 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
递回的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递回下去,但是这个算法总会结束,因为在每次的迭代(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');
}
}