冒泡排序:具体算法描述如下:
1、比较相邻的元素。如果第一个比第二个大,就交换他们两个。
2、对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
3、针对所有的元素重复以上的步骤,除了最后一个。
4、持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
分类 排序算法
数据结构 数组
最差时间复杂度 О(n2)
最优时间复杂度 О(n)
平均时间复杂度 О(n2)
最差空间复杂度 О(n) total, O(1) auxiliary
/**
* 冒泡排序
*/
public void maoPao() {
int[] nums = new int[]{8, 9, 2, 1, 4, 3, 5, 7, 6, 0};
for (int i = 0; i < nums.length - 1; i++) {
for (int j = i; j < nums.length; j++) {
if (nums[i] > nums[j]) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
}
print(nums);
}
简单选择排序
1、从第一个元素开始,循环
2、定义一个最小值索引记录 minIndex, 为当前值索引 i。
3、(当前minIndex元素 X ) 对比 剩余未排序的其他元素。
4、如果发现有小于X的元素,则将该值索引标记为 minIndex
5、重复步骤3,4后,交换 minIndex 和 i 的值。
分类 排序算法
数据结构 数组
最差时间复杂度 О(n2)
最优时间复杂度 О(n2)
平均时间复杂度 О(n2)
最差空间复杂度 О(n) total, O(1) auxiliary
选择排序的交换操作介于和次之间。选择排序的比较操作为次之间。选择排序的赋值操作介于和次之间。
比较次数O(n^2),比较次数与关键字的初始状态无关,总的比较次数N=(n-1)+(n-2)+...+1=n*(n-1)/2。 交换次数O(n),最好情况是,已经有序,交换0次;最坏情况是,逆序,交换n-1次。 交换次数比冒泡排序少多了,由于交换所需CPU时间比比较所需的CPU时间多,n值较小时,选择排序比冒泡排序快。
/**
* 简单选择排序
*/
public void simpleSelect() {
int[] nums = new int[]{8, 9, 2, 1, 4, 3, 5, 7, 6, 0};
for (int i = 0; i < nums.length - 1; i++) {
int min = i;
for (int j = i; j < nums.length; j++) {
if (nums[min] > nums[j]) {
min = j;
}
}
if (min != i) {
int temp = nums[i];
nums[i] = nums[min];
nums[min] = temp;
}
}
print(nums);
}
插入排序:具体算法描述如下:
1、从第一个元素开始,该元素可以认为已经被排序
2、取出下一个元素,在已经排序的元素序列中从后向前扫描
3、如果该元素(已排序)大于新元素,将该元素移到下一位置
3、重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
4、将新元素插入到该位置后
5、重复步骤2~5
平均来说插入排序算法复杂度为O(n2)。因而,插入排序不适合对于数据量比较大的排序应用。但是,如果需要排序的数据量很小,例如,量级小于千,那么插入排序还是一个不错的选择
/**
* 插值排序
*/
public void insert() {
int[] nums = new int[]{8, 9, 2, 1, 4, 3, 5, 7, 6, 0};
for (int i = 1; i < nums.length; i++) {
int j = i;
int data = nums[i];
while (j > 0 && nums[j - 1] > data) {
nums[j] = nums[j - 1];
j--;
}
nums[j] = data;
}
print(nums);
}
希尔排序:
核心:先将序列分成较多个子序列分别进行排序,再分成较少个子序列分别进行排序,直到最后为一个序列排序。
形象的说:比如先分成 8 个子序分别排序,再 4 个子序,再 2 个子序,最后 1 个(1个也就是全部序列啦)。
算法的最后一步就是普通的插入排序
在大数组中表现优异的步长串行是(斐波那契数列除去0和1将剩余的数以黄金分区比的两倍的幂进行运算得到的数列):
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946,
(1, 9, 34, 182, 836, 4025, 19001, 90358, 428481, 2034035, 9651787, 45806244, 217378076, 1031612713, …)
各类步长公式
public void shell() {
int[] nums = new int[]{8, 9, 2, 1, 4, 3, 5, 7, 6, 0};
int seg = 1;
while (seg < nums.length / 3) seg = seg * 3 + 1; // <O(n^(3/2)) by Knuth,1973>: 1, 4, 13, 40, 121, ...每次的步长。
for (; seg >= 1; seg /= 3) {
for (int i = seg; i < nums.length; i++) { //插入排序外皮开始, 以seq为递增
int j = i;
int data = nums[i];
while (j > (seg - 1) && nums[j - seg] > data) {
nums[j] = nums[j - seg];
j -= seg;
}
nums[j] = data;
}
}
print(nums);
}