1、直接插入排序
插入排序是一种最简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
public static void InsertSort(int[] array){
if(array == null || array.length == 0)
return ;
for(int i = 0;i < array.length; i++){
int value = array[i];
int j;
for( j = i - 1; j >= 0; j--){
if(value < array[j]){
array[j + 1] = array[j];
}else{
break;
}
}
array[j + 1] = value;
}
}
2、 希尔排序
希尔排序示意图
希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
插入排序在对几乎已经排好序的数据操作时, 效率高, 即可以达到线性排序的效率
但插入排序一般来说是低效的, 因为插入排序每次只能将数据移动一位
希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列,对所有的子序列同时分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
算法步骤:
1)选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
2)按增量序列个数k,对序列进行k 趟排序;
3)每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
public static void ShellSort(int[] array){
if(array == null || array.length == 0)
return ;
for(int gap = (array.length/2); gap > 0; gap/=2){
for(int i = gap; i < array.length; i++)
for(int j = i-gap; j>=0 && array[j]>array[j+gap]; j -= gap) {
int temp = array[j];
array[j] = array[j+gap];
array[j+gap] = temp;
}
}
}
3、直接选择排序
步骤:每次从未排序序列中选择最小(最大)元素放在已排序序列的尾部
public static void SelectSort(int[] array){
if(array == null || array.length == 0)
return ;
for(int i = 0;i < array.length; i++){
int minindex = array[i];
for(int j = i; j < array.length; j++){
if(array[j] < minindex)
minindex = j;
}
if(minindex != i){
int temp = array[i];
array[i] = array[minindex];
array[minindex] = temp;
}
}
}
4、堆排序
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
同时,我们对堆中的结点按层进行编号,将这种逻辑结构映射到数组中就是下面这个样子
该数组从逻辑上讲就是一个堆结构,我们用简单的公式来描述一下堆的定义就是:
大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]
小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]
算法步骤:
1)创建一个堆H[0..n-1]
2)把堆首(最大值)和堆尾互换
3)把堆的尺寸缩小1,并调用shift_down(0),目的是把新的数组顶端数据调整到相应位置
4) 重复步骤2,直到堆的尺寸为1
//本函数功能是:根据数组array构建大根堆
//从第i个元素开始向下调整
public static void adjustHeap(int []arr,int i,int length){
for(int k=i*2+1;k<length;k=k*2+1){//从i结点的左子结点开始,也就是2i+1处开始
if(k+1<length && arr[k]<arr[k+1]){//如果左子结点小于右子结点,k指向右子结点
k++;
}
if(arr[k] >arr[i]){//如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
int temp = arr[i];
arr[i] = arr[k];
i = k;
arr[k] = temp;
}else{
break;
}
}
}
//堆排序算法
public static void HeapSort(int array[]){
//1.构建大顶堆,目的只是保证堆顶元素值最大
//保证堆从上到下大致有序看,任意从节点到叶子节点的路径上元素是有序的
for(int i=array.length/2-1;i>=0;i--){
//从第一个非叶子结点(即array.length/2 - 1)从下至上,从右至左调整结构
adjustHeap(array,i,array.length);
}
//2.调整堆结构+交换堆顶元素与末尾元素,
for(int j=array.length-1;j>0;j--){
array[j] = array[0] ^ array[j];//将堆顶元素与末尾元素进行交换
array[0] = array[0] ^ array[j];
array[j] = array[0] ^ array[j];
adjustHeap(array,0,j);//重新对堆进行调整
}
}
5、冒泡排序
冒泡排序(Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
public static void BubbleSort(int[] array){
if(array == null || array.length == 0)
return ;
for(int i = array.length - 1;i > 0; i--){
for(int j = 0 ;j < i;j++ ){
if(array[j] > array[j+1]){
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
6、 快速排序
快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要Ο(n log n)次比较。在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。
快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。
public static void Qsort(int[] array,int start,int end) {
if(array == null || array.length == 0)
return ;
if(start > end)
return ;
else{
int i = start;
int j = end;
int flag = array[end];
while(i < j){
while(array[i] <= flag && i<j){
i++;
}
if(array[i] > flag && j > i){
array[j] = array[i];
array[i] = flag;
j--;
}
while(array[j] >= flag && j>i){
j--;
}
if(array[j] < flag && i<j){
array[i] = array[j];
array[j] = flag;
i++;
}
}
array[i] = flag;
Qsort(array,start,i - 1);
Qsort(array,i + 1,end);
}
}
7、归并排序
归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
算法步骤:
申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
设定两个指针,最初位置分别为两个已经排序序列的起始位置
比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针达到序列尾
将另一序列剩下的所有元素直接复制到合并序列尾
public static void MergeSort(int[] copy,int[] array,int start,int end){
if(array == null || array.length == 0)
return ;
if(start >= end)
return ;
int middle = (end - start )/2;
MergeSort(copy,array,start,start + middle);
MergeSort(copy,array,start + middle + 1,end);
int i = start + middle;
int j = end;
int index = end;
while(i >= start && i <= (start + middle) && j >= (start + middle + 1) && j <= end){
if(copy[i] > copy[j]){
array[index--] = copy[i--];
}else{
array[index--] = copy[j--];
}
}
while(i >= start && i <= (start + middle) && index >= start){
array[index--] = copy[i--];
}
while(j >= (start + middle + 1) && j <= end && index >= start){
array[index--] = copy[j--];
}
for(int m = start;m <= end;m++){
copy[m] = array[m];
}
}
8、基数排序 (即桶排序)
典型的以空间换时间,时间复杂度为线性时间