一、冒泡排序
冒泡排序实现简单,但运行效率较慢。算法思想是,设要排序的为数组A中的元素,遍历A.length-1次,每次找出待排序元素中最小的值放在相应位置,如:第一次遍历数组下标为A.length-1 到0的元素,将最小的值放在A[0]的位置,第二次遍历数组下标为A.length-1到1的元素,将最小值放在A[1]的位置。总共遍历 A.length-1次得到一个有序数组。这个算法的时间开销主要在比较和交换上。效率极低。
Java实现代码:
public class Bubble {
public static long[] BubbleSort(long[] a){
for(int i=a.length -1;i>0;i--){
for(int j=0;j<i ;j++){
if(a[j]>a[j+1]){
long temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
return a;
}
二、插入排序
插入排序适合少量元素的排序,插入排序算法将元素分为两组,一组是已经有序的,一组是待参与排序的。初始时,有序的组中仅有原数组的首元素,其后,不断从待排序的元素中取出一个插入到有序数组的合适位置,直至待排序数组为空。此过程类似于玩扑克牌中起牌的过程,手中的牌是有序的,桌子上的牌是待排序的,每次从桌上起一张牌插到手中的牌。插入排序算法最坏情况下插入排序运行时间为Θ(n^2)。
具体的Java实现代码如下:
注:float[] a为待排序的数组。
public static float[] InsertSort(float[] a)
{
if (a.length <= 1)
return a;
// 从第二个元素起 插到前面排列好的序列中
for(int i=1;i<a.length;i++){
float key = a[i]; //key为要插入的数据
int j = i -1;//标记要与Key比较的元素的下标0
while(j>=0&&key<a[j]){
a[j+1] = a[j];
j--;
}
a[j+1] = key;
}
return a;
}
三、 快速排序
最坏情况时间复杂度为Θ(n2)。虽然最坏情况表现很差,但是快速排序通常是实际应用中最好的选择,因为它的平均性能特别好,它的期望时间复杂度为Θ(n lg n) 而且Θ(nlg n)中隐含的常数因子非常小,此外,它还能在原址排序。
与归并排序一样,快速排序也使用了分治思想。大致思路是这样的:
1、 数组被划分成两个子数组(可能为空),这两个数组满足:左边数组中的每一个元素都不大于右边数组的任一个元素。
2、 对两个子数组重复上面操作,直至子数组长度小于等于1。
对于第一步操作,代码中用partition函数实现。主要思路如下:
对于数组A:
1、 数组的最后一个元素为哨兵;
2、 数组划分界线Div初始为-1;
3、 遍历数组中下标为0-A.length-2的元素进行以下操作:
- 若该元素小于A[A.length-1],该元素与A[Div+1]交换;
- Div加一;
4、 A[Div+1]与A[A.length-1]交换。
Java实现的代码如下:
private static float[] QuickSort(float[] a,int p,int r) {
// TODO Auto-generated method stub
if(p<r){
int q = partition(a,p,r);
QuickSort(a,p,q-1);
QuickSort(a,q+1,r);
}
return a;
}
// partition函数得到数组的一个下标 这个下标使得左边的元素都大于它 右边的元素都不小于它
private static int partition(float[] a,int p,int r){
float x = a[r];
int low = p - 1 ;// p-low存放比x小的 low-high存放比x大的
for(int j=p;j<r;j++){
if(a[j]<=x) {
// exchange a[low+1] with a[j]
float temp = a[low+1];
a[low+1] = a[j];
a[j] = temp;
low++;
}
}
// exchange a[low+1] with a[r]
float temp = a[r];
a[r] = a[low+1];
a[low+1] = temp;
low++;
return low;
}
四、归并排序
简言之,归并排序将两个有序的数组合并为一个新的有序数组
以扑克牌为例 两堆牌面朝上的有序扑克牌 每次取两堆中 最上面的较小的一张 直到一堆牌为空
private float[] MergeSort(float[] a)
{ if(a.length<=1) return a;
for(int i = 1;i<a.length;i=2*i)
for(int p = 0;p<a.length;p=p+2*i )
{
int r = p + 2*i -1;
int q = p + i -1;
if(q>a.length - 1) q = a.length - 1;
if(r>a.length - 1) r = a.length - 1 ;
Merge(a,p,q,r);
}
return a;
}
private static float[] Merge(float[] a,int p,int q,int r) // a为待排序数组 pqr为下标 p->q有序 q+1->r有序
{
int n1 = q - p + 1;
int n2 = r -q;
float[] L = new float[n1+1];
float[] R = new float[n2+1];
for(int i=0; i<n1;i++)
L[i] = a[p + i];
L[n1] = 99999;//哨兵位置
for(int i=0; i<n2; i++)
R[i] = a[q+i + 1];
R[n2] = 99999;//哨兵位置
// i和j标记R和L待比较的最小值的位置
int i = 0;
int j = 0;
// k标记a中插入位置
for(int k=p;k<=r;k++)
if(R[i]>L[j])
{
a[k] = L[j];
j++;
}
else
{
a[k] = R[i];
i++;
}
return a;
}
}
五、 希尔排序
希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。
希尔排序基于插入排序,但是增加了一个新的特性,大大地提高了插入排序的执行效率。对于插入排序而言,比较尴尬的地方在于,如果插入一个较大的数,它需要跟前面的元素进行大量的比较才能找到自己的位置,同时,在到达它的位置的过程中,也进行了大量的数据交换操作。而希尔排序通过加大插入排序中要比较的元素之间的间隔,并对这些有一定间隔的元素进行插入排序,从而可以使得元素大幅度的移动。希尔排序大约需要Θ(n*(lg n)2)时间。
算法大致实现思路:
1.与插入排序不同,比较不再仅局限于相邻元素,而是设置一个间隔h,A[i]与A[i+h]比较,A[i+h]再与A[i+2h]比较,比较的同时将小的元素交换到前面来。
2.逐步减小h至1,最终得到有序数组。
希尔排序比较尴尬的地方在于,这个间隔h怎么取值?
public static void shellSort(int[] data) {
int j = 0;
int temp = 0;
for (int increment = data.length / 2; increment > 0; increment /= 2) {
for (int i = increment; i < data.length; i++) {
temp = data[i];
for (j = i; j >= increment; j -= increment) {
if(temp > data[j - increment]){
data[j] = data[j - increment];
}else{
break;
}
}
data[j] = temp;
}
}
六、选择排序
选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。 选择排序是不稳定的排序方法。
选择排序法的第一层循环从起始元素开始选到倒数第二个元素,主要是在每次进入的第二层循环之前,将外层循环的下标赋值给临时变量,接下来的第二层循环中,如果发现有比这个最小位置处的元素更小的元素,则将那个更小的元素的下标赋给临时变量,最后,在二层循环退出后,如果临时变量改变,则说明,有比当前外层循环位置更小的元素,需要将这两个元素交换.
public static void selectSort(int[]a)
{
int minIndex=0;
int temp=0;
if((a==null)||(a.length==0))
return;
for(int i=0;i<a.length-1;i++)
{
minIndex=i;//无序区的最小数据数组下标
for(intj=i+1;j<a.length;j++)
{
//在无序区中找到最小数据并保存其数组下标
if(a[j]<a[minIndex])
{
minIndex=j;
}
}
if(minIndex!=i)
{
//如果不是无序区的最小值位置不是默认的第一个数据,则交换之。
temp=a[i];
a[i]=a[minIndex];
a[minIndex]=temp;
}
}
}