概念
排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。 我们这里说说八大排序就是内部排序。
当
n
n
n 较大,则应采用时间复杂度为
O
(
n
l
o
g
2
n
)
O(nlog2n)
O(nlog2n) 的排序方法:快速排序、堆排序或归并排序序。 快速排序:是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短;
1.插入排序—直接插入排序(Straight Insertion Sort)
基本思想:
将一个记录插入到已排序好的有序表中,从而得到一个新,记录数增1的有序表。即:先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。 要点:设立哨兵,作为临时存储和判断数组边界之用。
直接插入排序示例:
如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。
算法的实现:
package com;
public class InsertSort {
public static void main(String[] args) {
int a[] = {3,1,5,7,2,4,9,6,10,8};
InsertSort obj=new InsertSort();
System.out.println("初始值:");
obj.print(a);
obj.insertSort(a);
System.out.println("\n排序后:");
obj.print(a);
}
public void print(int a[]){
for(int i=0;i<a.length;i++){
System.out.print(a[i]+" ");
}
}
public void insertSort(int[] a) {
for(int i=1;i<a.length;i++){//从头部第一个当做已经排好序的,把后面的一个一个的插到已经排好的列表中去。
if(a[i]<a[i-1]){
int j;
int x=a[i];//x为待插入元素
a[i]=a[i-1];
for(j=i-1; j>=0 && x<a[j];j--){//通过循环,逐个后移一位找到要插入的位置。
a[j+1]=a[j];
}
a[j+1]=x;//插入
}
}
}
}
效率:
时间复杂度:
O
(
n
2
)
O(n^2)
O(n2).
其他的插入排序有二分插入排序,2-路插入排序。
2. 插入排序—希尔排序(Shell`s Sort)
希尔排序是1959 年由D.L.Shell 提出来的,相对直接排序有较大的改进。希尔排序又叫缩小增量排序。
基本思想:
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
操作方法:
选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1; 按增量序列个数k,对序列进行k 趟排序; 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
希尔排序的示例:
算法实现:
我们简单处理增量序列:增量序列d = {n/2 ,n/4, n/8 …1} n为要排序数的个数
即:先将要排序的一组记录按某个增量d(n/2,n为要排序数的个数)分成若干组子序列,每组中记录的下标相差d.对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2)对它进行分组,在每组中再进行直接插入排序。继续不断缩小增量直至为1,最后使用直接插入排序完成排序。
package com;
/*
* Java实现希尔排序(缩小增量排序)
* author:wyr
* 2016-7-14
*两个步骤:1,建堆 2,对顶与堆的最后一个元素交换位置
*/
public class ShellSort {
public static void main(String[] args) {
int a[] = {3,1,5,7,2,4,9,6,10,8};
ShellSort obj=new ShellSort();
System.out.println("初始值:");
obj.print(a);
obj.shellSort(a);
System.out.println("\n排序后:");
obj.print(a);
}
private void shellSort(int[] a) {
int dk = a.length/2;
while( dk >= 1 ){
ShellInsertSort(a, dk);
dk = dk/2;
}
}
private void ShellInsertSort(int[] a, int dk) {//类似插入排序,只是插入排序增量是1,这里增量是dk,把1换成dk就可以了
for(int i=dk;i<a.length;i++){
if(a[i]<a[i-dk]){
int j;
int x=a[i];//x为待插入元素
a[i]=a[i-dk];
for(j=i-dk; j>=0 && x<a[j];j=j-dk){//通过循环,逐个后移一位找到要插入的位置。
a[j+dk]=a[j];
}
a[j+dk]=x;//插入
}
}
}
public void print(int a[]){
for(int i=0;i<a.length;i++){
System.out.print(a[i]+" ");
}
}
}
希尔排序时效分析很难,关键码的比较次数与记录移动次数依赖于增量因子序列d的选取,特定情况下可以准确估算出关键码的比较次数和记录的移动次数。目前还没有人给出选取最好的增量因子序列的方法。增量因子序列可以有各种取法,有取奇数的,也有取质数的,但需要注意:增量因子中除1 外没有公因子,且最后一个增量因子必须为1。希尔排序方法是一个不稳定的排序方法。
3. 选择排序—简单选择排序(Simple Selection Sort)
基本思想:
在要排序的一组数中,选出最小(或者最大)的一个数与第1个位置的数交换;然后在剩下的数当中再找最小(或者最大)的与第2个位置的数交换,依次类推,直到第n-1个元素(倒数第二个数)和第n个元素(最后一个数)比较为止。
简单选择排序的示例:
操作方法:
第一趟,从n 个记录中找出关键码最小的记录与第一个记录交换;
第二趟,从第二个记录开始的n-1 个记录中再选出关键码最小的记录与第二个记录交换;
以此类推…
第i 趟,则从第i 个记录开始的n-i+1 个记录中选出关键码最小的记录与第i 个记录交换, 直到整个序列按关键码有序。
算法实现
package com;
/*
* Java实现希尔排序(缩小增量排序)
* author:wyr
* 2016-7-14
*两个步骤:1,建堆 2,对顶与堆的最后一个元素交换位置
*/
public class SimpleSelectSort {
public static void main(String[] args) {
int a[] = {3,1,5,7,2,4,9,6,10,8};
SimpleSelectSort obj=new SimpleSelectSort();
System.out.println("初始值:");
obj.print(a);
obj.selectSort(a);
System.out.println("\n排序后:");
obj.print(a);
}
private void selectSort(int[] a) {
for(int i=0;i<a.length;i++){
int k=i;//k存放最小值下标。每次循环最小值下标+1
for(int j=i+1;j<a.length;j++){//找到最小值下标
if(a[k]>a[j])
k=j;
}
swap(a,k,i);//把最小值放到它该放的位置上
}
}
public void print(int a[]){
for(int i=0;i<a.length;i++){
System.out.print(a[i]+" ");
}
}
public void swap(int[] data, int i, int j) {
if (i == j) {
return;
}
data[i] = data[i] + data[j];
data[j] = data[i] - data[j];
data[i] = data[i] - data[j];
}
}
简单选择排序的改进——二元选择排序
简单选择排序,每趟循环只能确定一个元素排序后的定位。我们可以考虑改进为每趟循环确定两个元素(当前趟最大和最小记录)的位置,从而减少排序所需的循环次数。改进后对n个数据进行排序,最多只需进行[n/2]趟循环即可。具体实现如下:
void SelectSort(int r[],int n) {
int i ,j , min ,max, tmp;
for (i=1 ;i <= n/2;i++) {
// 做不超过n/2趟选择排序
min = i; max = i ; //分别记录最大和最小关键字记录位置
for (j= i+1; j<= n-i; j++) {
if (r[j] > r[max]) {
max = j ; continue ;
}
if (r[j]< r[min]) {
min = j ;
}
}
//该交换操作还可分情况讨论以提高效率
tmp = r[i-1]; r[i-1] = r[min]; r[min] = tmp;
tmp = r[n-i]; r[n-i] = r[max]; r[max] = tmp;
}
}