简介
排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。
1.插入排序—直接插入排序(Straight Insertion Sort)
基本思想
将一个记录插入到已排序好的有序表中,从而得到一个新,记录数增1的有序表。即:先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。
要点:设立哨兵,作为临时存储和判断数组边界之用。
直接插入排序示例
算法代码实现
package sort;
/**
* 直接插入排序,按照数字从小到大排列<br>
* @author shenhaiwen
*
*/
public class InserSort {
public static int[] insertSort(int[] a){
int length = a.length;
for(int i=1;i<length;i++){
if(a[i] >= a[i-1]){ // 若是a[i]大于a[i-1],则序列不变
continue;
}
int j = i-1;
int x = a[i]; //复制为哨兵,即存储待排序元素
a[i] = a[i-1]; //先后移一个元素
while(j>=0 && x < a[j]){
a[j+1] = a[j];
j--;
}
a[j+1] = x;
}
return a;
}
public static void main(String[] args) {
int[] a = {5,2,45,2,6,21};
a = insertSort(a);
System.out.println("直接插入排序结果:");
for(int k=0;k<a.length;k++){
System.out.print(a[k]+",");
}
}
测试结果
效率
时间复杂度:O(n^2).
2. 插入排序—希尔排序(Shell`s Sort)
基本思想
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
操作方法
选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
按增量序列个数k,对序列进行k 趟排序;
每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
示例
算法实现
package sort;
/**
* 希尔排序
*
* @author shenhaiwen
*
*/
public class ShellSort {
/**
* 直接插入排序
*
* @param a
* @param d
*/
public static void insertSort(int[] a,int d){
int length = a.length;
for(int i=d;i<length;i++){//类似插入排序,只是插入排序增量是1,这里增量是d,把1换成d
if(a[i] >= a[i-d]){
continue;
}
int j = i-d;
int x = a[i];
a[i] = a[i-d];
while(j>=0 && x < a[j]){
a[j+d] = a[j];
j -= d;
}
a[j+d] = x; // 插入
}
}
/**
* 希尔排序
*
* @param a
* @return
*/
public static int[] shellSort(int[] a){
int length = a.length;
int k = length/2;
while(k>=1){
insertSort(a,k);
k = k/2;
}
return a;
}
public static void main(String[] args) {
int[] a = {8,5,1,2,45,2,6,21};
shellSort(a);
System.out.println("希尔插入排序结果:");
for(int k=0;k<a.length;k++){
System.out.print(a[k]+",");
}
}
}
测试结果
希尔排序方法是一个不稳定的排序方法。
3. 选择排序—简单选择排序(Simple Selection Sort)
基本思想
设所排序序列的记录个数为n,i 取 1,2,…,n-1 。
从所有n-i+1个记录(Ri,Ri+1,…,Rn)中找出排序码最小(或最大)的记录,与第i个记录交换。执行n-1趟 后就完成了记录序列的排序。
示例
算法实现
package sort;
/**
* 简单选择排序
*
* @author shenhaiwen
*
*/
public class SimpleSelectSort {
/**
* 简单选择排序
* @param a
*/
public static void simpleSelectSort(int[] a){
int length = a.length;
for(int i=0;i<length;i++){
int k=i;
for(int j=i+1;j<length;j++){
if(a[k] > a[j]){ //每次交换最小值
int m = a[k];
a[k] = a[j];
a[j] = m;
}
}
}
}
public static void main(String[] args) {
int[] a = {8,5,1,2,45,2,6,21};
simpleSelectSort(a);
System.out.println("简单选择排序结果:");
for(int k=0;k<a.length;k++){
System.out.print(a[k]+",");
}
}
}
测试结果
4. 选择排序—堆排序(Heap Sort)
堆排序是一种树形选择排序,是对直接选择排序的有效改进。
TODO
5. 交换排序—冒泡排序(Bubble Sort)
基本思想
冒泡排序通过重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来,直到没有再需要交换的元素为止(对n个项目需要O(n^2)的比较次数)。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
示例
算法实现
/**
* 冒泡排序
*
* @author shenhaiwen
*
*/
public class BubbleSort {
public static int[] bubbleSort(int[] a){
int length = a.length;
for(int i=0;i<length;i++){
for(int j=0;j<length-i-1;j++){
if(a[j]>a[j+1]){ // 若大于,则交换
int temp = a[j+1];
a[j+1] = a[j];
a[j] = temp;
}
}
}
return a;
}
public static void main(String[] args) {
int[] a = {8,5,1,2,45,2,6,21};
bubbleSort(a);
System.out.println("冒泡排序结果:");
for(int k=0;k<a.length;k++){
System.out.print(a[k]+",");
}
}
}
结果
6. 交换排序—快速排序(Quick Sort)
基本思想
快速排序(Quicksort)是对冒泡排序的一种改进,又称划分交换排序(partition-exchange sort)。
快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为两个子序列(sub-lists)。
1)选择一个基准元素,通常选择第一个元素或者最后一个元素,
2)通过一趟排序讲待排序的记录分割成独立的两部分,其中一部分记录的元素值均比基准元素值小。另一部分记录的 元素值比基准值大。
3)此时基准元素在其排好序后的正确位置
4)然后分别对这两部分记录用同样的方法继续进行排序,直到整个序列有序。