1 冒泡排序
1.1 算法描述
- 比较相邻的元素。如果第二个比第一个小,就交换它们两个;
- 对每一对相邻元素作同样的工作,从最后一个到当前批次的开始下标i,这样在最上面元素会是最小的数;
- 针对所有的元素重复以上的步骤,除了最后一个;
- 下标i+1,重复步骤1~3,直到排序完成
1.2 算法分析
1.2.1 时间复杂度
- 平均:O(n2)
- 最优:O(n) 已经排好序
- 最坏:O(n2)
1.2.2 空间复杂度
O(1)
1.2.3 稳定性
稳定
1.3 算法实现
/**
* 冒泡排序
*
* @param array
* @return
*/
public void bubbleSort(int[] array) {
boolean isChange = true;
for (int i = 0; i < array.length - 1 && isChange == true; i++) {
isChange = false;
for (int j = array.length - 1; j > i; j--) {
if (array[j] < array[j - 1]) {
isChange = true;
array[j] = array[j] + array[j - 1];
array[j - 1] = array[j] - array[j - 1];
array[j] = array[j] - array[j - 1];
}
}
}
}
2 选择排序
2.1 算法描述
- 下标i从0开始到length-1结束,选择出最小的下标和i进行交换;
- 下标i+1,重复步骤1,直到i=length-2
2.2 算法分析
2.2.1 时间复杂度
- 平均:O(n2)
- 最优:O(n2)
- 最坏:O(n2)
2.2.2 空间复杂度
O(1)
2.2.3 稳定性
不稳定:[3,3,1]。第一个3会到第二个3后面
2.3 算法实现
/**
* 选择排序
*
* @param array
* @return
*/
public void selectionSort(int[] array) {
for (int i = 0; i < array.length - 1; i++) {
int minIndex = i;
for (int j = i + 1; j < array.length; j++) {
if (array[minIndex] > array[j]) {
minIndex = j;
}
}
int temp=array[i];
array[i] = array[minIndex];
array[minIndex] = temp;
}
}
3 插入排序
3.1 算法描述
- 从第一个元素开始,该元素可以认为已经被排序;
- 取出下一个元素A,在已经排序的元素序列中从后向前扫描;
- 如果该元素(已排序)大于元素A,将该元素移到下一位置;
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
- 将新元素插入到该位置后;
- 重复步骤2~5。
3.2.1 时间复杂度
- 平均:O(n2)
- 最优:O(n) 已经排好序
- 最坏:O(n2)
3.2.2 空间复杂度
O(1)
3.2.3 稳定性
稳定
3.3 算法实现
/**
* 插入排序
*
* @param array
* @return
*/
public void insertionSort(int[] array) {
for (int i = 1; i < array.length; i++) {
int j = i;
int temp = array[i];
for (; j > 0; j--) {
if (temp >= array[j - 1]) {
break;
}
array[j] = array[j - 1];
}
array[j] = temp;
}
}
4 希尔排序
4.1 算法描述
- 插入排序在小范围数组和已经排好序的数组效果最好,所以希尔排序使用了缩小增量排序
- 选择增量gap=length/2,缩小增量继续以gap = gap/2的方式,这种增量选择我们可以用一个序列来表示,{n/2,(n/2)/2...1},称为增量序列
- 根据增量间隔来依次分组进行插入排序
- 如gap=5,从第6个数n开始对{n-5,n-5-5,....1}进行插入排序,直到n=length
4.2.1 时间复杂度
- 平均:O(n1.3)
- 最优:O(n) 已经排好序,第一次间隔为1
- 最坏:O(n2)
4.2.2 空间复杂度
O(1)
4.2.3 稳定性
不稳定:[1,3,3,1]。第一个3会到第二个3后面
4.3 算法实现
/**
* 希尔排序
*
* @param array
* @return
*/
public void shellSort(int[] array) {
int length = array.length / 2;
for (; length > 0; length = length / 2) {
for (int i = length; i < array.length; i++) {
int j = i;
int temp = array[i];
for (; j >= length; j -= length) {
if (temp >= array[j - length]) {
break;
}
array[j] = array[j - length];
}
array[j] = temp;
}
}
}
5 归并排序
5.1 算法描述
- 把长度为n的输入序列分成两个长度为n/2的子序列;
- 对这两个子序列分别继续进行n/2拆分,直到长度为1;
- 将两个排序好的子序列,从各自的最左端进行比较,把最小的放到新数组里面,等比较完成后再复制到原数组相应的位置。
5.2.1 时间复杂度
- 平均:O(nlogn)
- 最优:O(nlogn)
- 最坏:O(nlogn)
5.2.2 空间复杂度
O(n) 递归需要的栈帧,不用递归就是 O(1)
5.2.3 稳定性
稳定
5.3 算法实现
/**
* 归并排序
*
* @param array
* @return
*/
public void mergeSort(int[] array) {
mergeSort(0, array.length - 1, array, new int[array.length]);
}
public void mergeSort(int start, int end, int[] array, int[] temp) {
if (end > start) {
int mid = (start + end) / 2;
mergeSort(start, mid, array, temp);
mergeSort(mid + 1, end, array, temp);
int left = start;
int right = mid + 1;
for (int i = start; i <= end; i++) {
if (left > mid) {
temp[i] = array[right++];
} else if (right > end) {
temp[i] = array[left++];
} else if (array[left] <= array[right]) {
temp[i] = array[left++];
} else {
temp[i] = array[right++];
}
}
for (int i = start; i <= end; i++) {
array[i] = temp[i];
}
}
}
6 快速排序
6.1 算法描述
- 从数列中挑出一个元素,称为 “基准”(pivot),通常是第一个;
- 定义第一个为左下标,最后一个为右下标,从右下标开始向左移动依次与基准比较,找到第一个小于基数的下标,移动左下标找到第一个大于基数的下标,交换左右下标的数值,直到左下标等于又下标,此时这个基数就处于中间位置,即它的左边都小于等于它,右边都大于等于它;
- 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列分别进行1-2
6.2.1 时间复杂度
- 平均:O(nlogn)
- 最优:O(nlogn)
- 最坏:O(n2)
6.2.2 空间复杂度
O(nlogn) 递归需要的栈帧,不用递归就是 O(1)
6.2.3 稳定性
不稳定:[3,3,1] 第一个3会到第二个3后面
6.3 算法实现
/**
* 快速排序
*
* @param array
* @return
*/
public void quickSort(int[] array) {
quickSort(0, array.length - 1, array);
}
public void quickSort(int start, int end, int[] array) {
if (start >= end) {
return;
}
int left = start;
int right = end;
while (right > left) {
while (right > left && array[right] >= array[start]) {
right--;
}
while (right > left && array[left] <= array[start]) {
left++;
}
if (right > left) {
array[right] = array[right] + array[left];
array[left] = array[right] - array[left];
array[right] = array[right] - array[left];
right--;
}
}
if (start != left) {
array[start] = array[start] + array[left];
array[left] = array[start] - array[left];
array[start] = array[start] - array[left];
}
quickSort(start, left - 1, array);
quickSort(left + 1, end, array);
}
7 堆排序
7.1 算法描述
- 构建堆结构(以最大堆为例,最小堆反过来即可),即a[i]>=a[2i+1]&&a[i]>=a[2i+2]
- 按照二叉树定义,非叶子结点对应的叶子结点是2i+1和2i+2,同样节点n反过来求他的父节点,就可以用这个公式2i+1=n,如果求出来的是整数那么n就是左节点,如果是小数就是右节点;
- 先从最后一位的下标通过上述公式反求出最后一个非叶子节点,然后和他的左右节点找出最大的换到那个节点数,如果进行了交换,那就对交换的节点进行堆调整,就是对这个节点的左右节点这接着进行此步骤,然后下标减1,直到到0
- 然后把第一个也就是最大的和最后一个e进行交换,再将数组的0到e-1位继续进行2-4
7.2.1 时间复杂度
- 平均:O(nlogn)
- 最优:O(nlogn)
- 最坏:O(nlogn)
7.2.2 空间复杂度
O(1)
7.2.3 稳定性
不稳定:[3,3,1] 第一个3会到第二个3后面
7.3 算法实现
/**
* 堆排序
*
* @param array
* @return
*/
public void heapSort(int[] array) {
int length = array.length;
for (int a = length - 1; a > 0; a--) {
for (int i = (a - 1) / 2; i >= 0; i--) {
heapSort(array, i, a);
}
swap(array, 0, a);
}
}
public void heapSort(int[] array, int i, int end) {
int left = 2 * i + 1;
int right = 2 * i + 2;
if (left > end) {
return;
}
int maxIndex = right <= end && array[right] > array[left] ? right : left;
if (array[i] < array[maxIndex]) {
swap(array, i, maxIndex);
heapSort(array, maxIndex, end);
}
}
public void swap(int[] array, int i, int j) {
array[i] = array[i] + array[j];
array[j] = array[i] - array[j];
array[i] = array[i] - array[j];
}
8 计数排序
8.1 算法描述
- 找出待排序的数组中最大和最小的元素的差值n,构建长度为n+1的数组C;
- 数组中的值i,存入数组C的第i-最小值项,每出现一次,在C相应位置加1;
- 遍历数组C,将不为0的下标作为值,放到原数组中,C的值是多少,就往原数组里面添加几次C的下标
- 缺点是数据离散程度大的话,会浪费很大资源,而且不能比较小数,差值n不能大余int的最大值
8.2.1 时间复杂度
- 平均:O(n+k)
- 最优:O(n+k)
- 最坏:O(n+k)
8.2.2 空间复杂度
O(n+k)
8.2.3 稳定性
稳定
8.3 算法实现
/**
* 计数排序
*
* @param array
* @return
*/
public void countingSort(int[] array) {
int min = array[0], max = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] < min) {
min = array[i];
} else if (array[i] > max) {
max = array[i];
}
}
int length = max - min + 1;
int[] temp = new int[length];
for (int item : array) {
temp[item - min]++;
}
int index = 0;
for (int i = 0; i < temp.length; i++) {
while (temp[i] > 0) {
temp[i]--;
array[index++] = i + min;
}
}
}
9 桶排序
9.1 算法描述
- 设置一个定量的数组当作空桶,桶的范围是最大值和最小值的差值除桶数量;
- 遍历输入数据,并且把数据一个一个放到对应的桶里去;
- 对每个不是空的桶进行插入排序;
- 从不是空的桶里把排好序的数据拼接起来。
9.2.1 时间复杂度
- 平均:O(n+k)
- 最优:O(n) 都在一个桶内,并且已经排好序(插入排序的最优)
- 最坏:O(n2) 都在一个桶内,并且已经是倒序(插入排序的最坏)
9.2.2 空间复杂度
O(n+k)
9.2.3 稳定性
稳定
9.3 算法实现
/**
* 桶排序
*
* @param array
* @return
*/
public void bucketSort(int[] array) {
int bucketNum = 3;
LinkedList[] linkedList = new LinkedList[bucketNum];
int min = array[0], max = array[0];
for (int item : array) {
if (item < min) {
min = item;
} else if (item > max) {
max = item;
}
}
int bucketSize = (max - min) / bucketNum + 1;
for (int item : array) {
int bucketIndex = (item - min) / bucketSize;
if (linkedList[bucketIndex] == null) {
linkedList[bucketIndex] = new LinkedList();
}
LinkedList list = linkedList[bucketIndex];
Iterator<Integer> iterator = list.iterator();
int index = 0;
while (iterator.hasNext()) {
if (item < iterator.next()) {
break;
}
index++;
}
list.add(index, item);
}
int index = 0;
for (int i = 0; i < linkedList.length; i++) {
LinkedList<Integer> list = linkedList[i];
if (list == null) {
continue;
}
for (int item : list) {
array[index++] = item;
}
}
}
10 基数排序
10.1 算法描述
- 设置0-19,20个数组(包括负数),
- 先按照个位先排序,然后重新赋值到原数组;
- 再按照高位排序,然后再重新赋值到原数组;
- 依次类推,直到最高位。
- 缺点:不支持小数
10.2.1 时间复杂度
- 平均:O(n*k)
- 最优:O(n*k)
- 最坏:O(n*k)
10.2.2 空间复杂度
O(n+k)
10.2.3 稳定性
稳定
10.3 算法实现
/**
* 基数排序
*
* @param array
* @return
*/
public void radixSort(int[] array) {
int max = 0;
for (int item : array) {
item = item >= 0 ? item : -item;
if (item > max) {
max = item;
}
}
LinkedList[] linkedList = new LinkedList[20];
int down = 1;
while (down <= max) {
for (int item : array) {
int remain = item / down % 10;
int index = item >= 0 ? 10 + remain : 9 + remain;
if (linkedList[index] == null) {
linkedList[index] = new LinkedList();
}
linkedList[index].add(item);
}
down *= 10;
int index = 0;
for (LinkedList linked : linkedList) {
if (linked != null) {
Iterator<Integer> iterator = linked.iterator();
while (iterator.hasNext()) {
array[index++] = iterator.next();
iterator.remove();
}
}
}
}
}