排序算法总结:
逐个分析排序算法:
1.插入类排序:像打扑克一样,第一张牌不用整理,从第二张开始将牌和之前的所有牌比较并插入到正确位置上。算法为:
★查找待插入元素的插入位置
★此位置之后的所有元素后移一位
★插入即可
(1)直接插入排序:
设一个监视哨r[0],用来存放待插记录,从第二个元素开始,和已经排好序的数列从后向前比较,直到找到大于待插记录停止,将比较过的数列整体后移,然后插入。
//此方法最坏时间复杂度为o(n*n),因为比较一趟,移动一趟;空间复杂度为o(1),因为只占用了一个监视哨;此方法是稳定的
public class test1 {
public static void main(String[] args) {
int i, j;
int r[] = { 0, 0, 1, 9, 5, 15, 3, -5 };// 注意,第一个0是监视哨,占位置而已
for (i = 2; i < r.length; i++) {//不是<=,因为0号位置没有用到
r[0] = r[i];
if (r[i] < r[i - 1]) {//当待排元素小于前一个元素时,才比较,否则不用比较。
for (j = i - 1; r[j] > r[0]; j--) {//注意判断条件是大于
r[j + 1] = r[j];//后移序列
r[j] = r[0];//插入操作
}
} else {
continue;
}}
for (i = 1; i < r.length; i++) {
System.out.println(r[i]);
}}}
(2)折半插入排序
同样设一个监视哨来存放当前待排元素,设置两个指针low和high,用中间值mid来和待排元素比较
//时间复杂度:移动加比较,仍为o(n*n),空间复杂度仍为O(1).且是稳定的。
public class test1 {
public static void main(String[] args) {
int i, j;
int low, high, mid;
int a[] = { 0, 0, -4, 25, 17, 1, -1, 5, 80 };
for (i = 2; i < a.length; i++) {
a[0] = a[i];
if (a[i] < a[i - 1]) {
low = 1;
high = i - 1;
while (low <= high) {
mid = (low + high) / 2;
if (a[mid] < a[0]) {
low = mid + 1;
} else {
high = mid - 1;
}}
for (j = i - 1; j >= low; j--) {
a[j + 1] = a[j];
a[j] = a[0];
}} else {
continue;}}
for (i = 1; i < a.length; i++) {
System.out.print(a[i]);
System.out.print(" ");
}}}
(3)希尔排序:
2.交换类排序:对待排序的关键字两两进行比较,只要发现为逆序就进行交换,知道没有逆序的记录为止。
(1)冒泡排序:依次比较相邻两个关键字的大小,逆序则交换,最终每比较一趟,最大或者最小的数字沉到底。可以设置一个标志位flag,用来跟踪判断序列是否已完成排序。
时间复杂度:最优情况下,序列已有序,时间复杂度为o(n),最坏情况下,序列完全是乱的,则需要o(n*n)的时间复杂度。
是一种稳定的算法且空间复杂度为o(1).
//注意设置标志位a[0],用来实现交换过程。
public class test1 {
public static void main(String[] args) {
int i, j;
int a[] = {0, 46, 25, 68, 33, 33, 19, 12, 80};
System.out.println(a.length)
for(j=1; j < a.length-1 ;j++) {//外层循环,循环次数不变
for(i=1; i < a.length-j; i++) {//内层循环比较然后交换,循环次数依次减少
if(a[i] > a[i+1]) {
a[0] = a[i];
a[i] = a[i+1];
a[i+1] = a[0];
}}}
for(i=1; i < a.length; i++) {
System.out.print(a[i]+" ");
}}}
(2)快速排序:几乎是最快的排序方法,采用分治的思想。
分治思想:将原问题分解为若干个规模更小但结构和原问题相似的子问题,递归的解这些子问题,然后将这些子问题的解组合为原问题的解
快排的思想:选择一个枢轴,设置high和low.两头同步开始交替比较,关键字小于枢轴的均移到枢轴之前,关键字大于枢轴的均移到枢轴之后。
public class test2 {
static void quicksort(int n[], int low, int high) {
if (low < high) {
int dp = partition(n, low, high);
quicksort(n, low, dp - 1);
quicksort(n, dp + 1, high);}}//递归的过程
static int partition(int n[], int low, int high) {//一趟比较的过程
int pivot = n[low];
while (low < high) {
while (low < high && n[high] >= pivot) high--;
if (low < high) n[low++] = n[high];
while (low < high && n[low] <= pivot) low++;
if (low < high) n[high--] = n[low];
}
n[low] = pivot; return low;
}
public static void main(String[] str) {//主函数负责初始化和显示
int n[] = { 0, -1, 53, 1, 36, 84, 19, 93, 113, 45, 23 };
quicksort(n, 1, 10);
for (int i = 1; i < 10; i++)
System.out.print(n[i] + " ");}}
3.选择类排序:基本思想:k初始值为i=1的值,从所有剩下的记录中按顺序寻找小于关键字的记录,找到后将其位置赋给k,比较i和k的值是否相等,不相等则交换即可。
(1)简单选择:时间复杂度为o(n*n),空间复杂度为o(1),排序方式不稳定
public class test1 {
static void sort(int a[]) {
for (int i = 0; i <= a.length - 1; i++) {
int k = i;
for (int j = i + 1; j <= a.length - 1; j++) {
if (a[j] < a[k])
k = j;}
if (k != i) {
int t = a[i];
a[i] = a[k];
a[k] = t;
}}}
public static void main(String[] args) {
int a[] = { 1, -1, 3, 14, 0 };
sort(a);
for (int i = 0; i <= a.length - 1; i++) {
System.out.println(a[i] + " ");
}}}