1,冒泡算法实现
冒泡算法是最简单的排序算法。
冒泡算法原理:从左到右相临的元素进行比较,前一个元素比后一个元素大,就进行交换。每遍历一轮就会找到元素里的最大值,交换到最右边的位置。
//c语言代码
int array[] = {99,33,2,96,55,66,75,7,23};
int length;
int temp;
length = sizeof(array) / sizeof(array[0]);
for (int end = length - 1; end > 0; end --) {
for (int begain = 1; begain <= end; begain ++) {
if (array[begain] < array[begain - 1]) {
temp = array[begain];
array[begain] = array[begain -1];
array[begain - 1] = temp;
}
}
}
//Java代码
int array[] = {22,45,32,1,88,77,98,56,54,34,21};
for(int end = array.length - 1; end > 0; end --){
for(int begain = 1; begain <= end; begain ++){
if(array[begain] < array[begain - 1]){
int temp = array[begain];
array[begain] = array[begain - 1];
array[begain - 1] = temp;
}
}
}
1.1,冒泡算法-优化1
如果冒泡算法的序列是完全有序的时候,就没必要不断的比较,可以提前终止冒泡排序。
//Java代码
//有序数组
int array[] = {2,4,5,7,8,17,22,26,34,44,45,49,50,51,57,58,59};
for(int end = array.length - 1; end > 0; end --){
//记录后一个序列是否比前一个大
boolean sorted = true;
for(int begain = 1; begain <= end; begain ++){
if(array[begain] < array[begain - 1]){
int temp = array[begain];
array[begain] = array[begain - 1];
array[begain - 1] = temp;
sortedIndex = begain;
sorted = false;
}
}
//如果都是比前一个大,break
if (sorted) break;
}
1.2,冒泡算法-优化2
如果序列的尾部已经出现了局部的有序,我们可以记录最后一次交换的位置,减少比较次数。
//Java代码
//尾部的序列是有序的
int array[] = {22,45,32,1,88,77,32,56,54,34,21,90,93,95,97,98,99};
for(int end = array.length - 1; end > 0; end --){
//记录最1次交换的位置
int sortedIndex = 1;
for(int begain = 1; begain <= end; begain ++){
if(array[begain] < array[begain - 1]){
int temp = array[begain];
array[begain] = array[begain - 1];
array[begain - 1] = temp;
//最后1次交换的位置
sortedIndex = begain;
}
}
end = sortedIndex;
}
1.3,冒泡排序的复杂度
-
最坏,平均时间复杂度:O(n²)
-
最好的时间复杂度:O(n)
-
空间复杂度:O(1)
2,排序算法的稳定性
2.1,如果相等的两个元素,在排序前后的相对位置保持不变,那么这就是稳定的排序。
-
排序前:5, 1, 3(1), 4, 6, 3(2)
-
稳定的排序:1, 3(1), 3(2), 4, 5, 6
-
不稳定的排序:1, 3(2), 3(1), 4, 5, 6
2.2,对自定义的对象进行排序是,稳定性会影响到最终的结果。
- 当排序是一对多进行的时候,比如张三和小明的成绩是一样的时候,是否是稳定排序就会影响到结果
- 冒泡排序是稳定的排序算法
3,原地算法
3.1,何为原地算法?
- 不依赖额外的资源或者依赖少数的额外资源,仅依靠输出来覆盖输入的称为原地算法。
- 空间复杂度为O(1) 的都可以认为是原地算法
- 非原地算法:Not-in-place 或 Out-of-place
- 冒泡算法属于:In-place
4,选择排序
4.1,执行流程
-
从元素里面找出最大的那个元素,然后将最大的元素与最末尾位置的元素进行交换。执行完一轮以后,最末尾位置的元素就是最大的。
-
忽略 1 中找到的最大的元素,重复执行步骤 1。
-
选择排序的交换次数远小于冒泡排序,选择排序的平均性能高于冒泡排序。
-
代码如下
int array[] = {22,45,32,1,88,77,32,56,54,34,21,90,93,95,97,98,99}; for(int end = array.length - 1; end > 0; end --){ //记录最大值的下标 int max = 0; for(int begain = 1; begain <= end; begain ++){ if(array[max] < array[begain]){ //获取最大值的下标 max = begain; } } //将最大值与末尾位置进行交换 int temp = array[end]; array[end] = array[max]; array[max] = temp; }
4.2,复杂度
- 最好,最坏,平均时间复杂度:O(n²)
- 空间复杂度:O(1)
- 属于不稳定排序
4.3,选择排序的优化
- 可以使用堆排序来进行优化
- 堆排序可以认为是对选择排序的一种优化
5,堆排序
5.1,执行流程
- 对原来的序列进行原地建堆。
- 重复执行以下步骤,直到堆的元素数量为 1 。
- 交换堆顶的元素与尾元素。
- 堆的元素数量减 1 。
- 对 0 的位置进行siftDown操作
5.2,代码实现
public class duiDemo {
static int heapSize;
static int[] array;
public static void main(String[] args) {
int arr[] = { 22, 45, 32, 1, 88, 77, 32, 56, 54, 34, 21, 90, 93, 95, 97, 98, 99 };
array = arr;
//原地建堆
heapSize = array.length;
for (int i = (heapSize >> 1) - 1; i >= 0; i--) {
siftDown(i);
}
while (heapSize > 1){
//交换堆顶元素和尾部元素
swap(0, --heapSize);
// 对0位置进行siftDown(恢复堆的性质)
siftDown(0);
}
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + "-");
}
System.out.print("hello java");
}
public static void siftDown(int index) {
int element = array[index];
int half = heapSize >> 1;
while (index < half){ //index必须是非叶子节点
//默认是左边跟父节点比
int childIndex = (index << 1) + 1;
int child = array[childIndex];
int rightIndex = childIndex + 1;
//又子节点比左子节点大
if (rightIndex < heapSize && cmp(array[rightIndex], child) > 0){
child = array[childIndex = rightIndex];
}
//大于等于子节点
if (cmp(element, child) >= 0) break;
array[index] = child;
index = childIndex;
}
array[index] = element;
}
/*
* 返回值等于0,代表 v1 == v2
* 返回值小于0,代表 v1 < v2
* 返回值大于0,代表 v1 > v2
*/
static int cmp(int v1, int v2) {
return v1 - v2;
}
/*
* 数组交换
*/
static void swap(int i1, int i2) {
int tmp = array[i1];
array[i1] = array[i2];
array[i2] = tmp;
}}
5.3,复杂度
- 最好,最坏,时间复杂度:O(nlogn)
- 空间复杂度:O(1)
- 属于不稳定排序