一.概念
两两比较,发生逆序则交换
二.冒泡排序
public static void main(String[] args) {
int arr[] = new int[]{1, 8, 6, 9, 9, 4, 7, 3, 8, 9, 3, 2, 7};
int n=arr.length;//n个数
int m; //m趟
for (m = 0; m < n - 1; m++) {
//比较n-m次,n-m-1因为arr[j+1]会使用最后一个元素
for (int j = 0; j < n - m- 1; j++) {
if (arr[j] > arr[j + 1]) {
int x = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = x;
}
}
}
for (int k = 0; k < arr.length; k++) {
System.out.print(arr[k] + "\t");
}
}
public static void main(String[] args) {
int arr[] = new int[]{1, 8, 6, 9, 9, 4, 7, 3, 8, 9, 3, 2, 7};
int n=arr.length;//n个数
int m; //m趟
int flag=1;//是否有序标志
for (m = 0; m < n - 1&&flag==1; m++) {
flag=0;//如果没交换则0
for (int j = 0; j < arr.length - m- 1; j++) {
if (arr[j] > arr[j + 1]) {
int x = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = x;
flag=1;//交换则标志
}
}
}
for (int k = 0; k < arr.length; k++) {
System.out.print(arr[k] + "\t");
}
}
最好情况,数组已经正序,只需要1趟(有flag),比较n-1次,不需要交换。
最坏情况,数组逆序,需要n-1趟,第一趟比较n-1,第二趟n-...
效率比其他O(n^2)算法好
三.快速排序
用到递归,递归结束条件:子表元素只剩一个
privotkey:中心元素
public static void main(String[] args) {
// int arr[] = new int[]{0, 1, 8, 6, 9, 9, 4, 7, 3, 8, 9, 3, 2, 7};
int[] arr = new int[]{0, 9, 7, 8, 6, 5, 4, 3, 2, 1};
sort(arr, 1, arr.length - 1);
for (int i = 1; i < arr.length; i++) {
System.out.print(arr[i] + "\t");
}
}
private static void sort(int[] arr, int low, int high) {
if (arr.length == 1) {
return;
}
int part = part(arr, low, high);
if (low < part) //low<part 元素不止一个才有排序意义
sort(arr, low, part);
if (high > part + 1)
sort(arr, part + 1, high);
}
//找到中间值的位置,将其分成两个数组,左边比中间值小或相等,右边比中间值小或相等
private static int part(int[] arr, int low, int high) {
// System.out.print("low="+low);
arr[0] = arr[low]; //将数组第一个元素作为 中间值,移动到哨兵;
// 用了第一个元素做中间值,假设最终位置是9,在遍历到5时,5左的位置已经是全部小于哨兵了
while (low < high) {
//从后往前,找一个<哨兵的值,移动到 low位置 !!!注意相等的值不移动
while (low < high && arr[0] <= arr[high]) {
high--;
}
//找到high是比哨兵小的位置, 把high元素移动到左边后,high处认为空
//如果遍历一遍没有找到,则high 必定和 low相同,赋值下也没关系;同时证明右边都比哨兵大,此时 high low相同,不会再继续执行,且找到了中间值位置达成目的
arr[low] = arr[high];
//high处为空,从前往后,找比哨兵大的位置 !!!注意相等的值不移动
while (low < high && arr[0] >= arr[low]) {
low++;
}
//找到low是比哨兵大的元素,移动到右边后, low处认为空元素
//如果遍历一遍没有找到,则high 必定和 low相同,赋值下也没关系
arr[high] = arr[low];
}
//经过上个循环,分成了左右两数组
//将中间值放在low,low
arr[low] = arr[0];
return low;
}
part方法时间复杂度O(n);
sort方法执行part,假设数组长度n,每个子表长度为1时不再执行part,n/2/2/2...=1 n/ (x^2)=1 n=x^2 x=logn
需要O(logn)的栈空间
数组本身有序,则退化成冒泡排序
数组越乱越好,如果基本有序,则需要改变选取划分元素的方法,比如选取中间位置的元素,而非第一个元素,不过即便最坏情况也有O(n2),不会太差。
四.参考直接插入排序,设计一个交换排序
直接插入排序,是将待排序的数字 插入到已经排好序的序列。
我们可以将待排序的数字 交换到已经排好序的序列合适位置。
public static void main(String[] args) {
int arr[] = new int[]{1, 8, 6, 9, 9, 4, 7, 3, 8, 9, 3, 2, 7};
for (int i = 0; i < arr.length; i++) {
for (int j = i; j > 0; j--) {
if (arr[j] < arr[j - 1]) {
int x = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = x;
}
}
}
for (int k = 0; k < arr.length; k++) {
System.out.print(arr[k] + "\t");
}
}