Java 几种排序法
2010-04-30 10:30
337 查看
这里主要对8种排序算法做个总结,分别是插入排序,选择排序,冒泡排序,希尔排序,归并排序,堆排序,快速排序以及基数排序。
1、 插入排序
比较和交换的时间复杂度为O(n^2),算法自适应,对于数据已基本有序的情况,时间复杂度为O(n),算法稳定,开销很低,适合于数据已基本有序或者数据量小的情况。
2、 选择排序
算法不稳定,O(1)的额外的空间,比较的时间复杂度为O(n^2),交换的时间复杂度为O(n),并不是自适应的。在大多数情况下都不推荐使用。只有在希望减少交换次数的情况下可以用。
3、 冒泡排序
算法稳定,O(1)的额外的空间,比较和交换的时间复杂度都是O(n^2),自适应,对于已基本排序的算法,时间复杂度为O(n)。冒泡算法的许多性质和插入算法相似,但对于系统开销高一点点。
4、 希尔排序
希尔排序并不稳定,O(1)的额外空间,时间复杂度为O(N*(logN)^2)。这中算法是基于插入排序的。最坏的情况下的执行效率和在平均情况下的执行效率相比相差不多。
5、 归并排序
归并算法稳定,数组需要O(n)的额外空间,链表需要O(log(n))的额外空间,时间复杂度为O(nlog(n)),算法不是自适应的,不需要对数据的随机读取。
6、java堆排序的实现
7、 快速排序
快速排序不稳定,O(log(n))的额外空间,时间复杂度为O(nlog(n)),不是自适应的。
8、 基数排序
以基数是10为例
① 根据数据项个位上的值,把所有的数据分为10组。
② 然后对这10组数据项重新排列:把所有关键字是以0结尾的数据排在最后面,然后是关键字结尾时1的数据项,照此顺序直到以9结尾的数据项。这个步骤被称为第一趟子排序。
③ 在第二趟子排序中,再次把所有的数据项分为10组,但是这一次是根据数据项十位上的值来分组。这次分组不能改变先前的排序顺序。也就是说,第二趟排序之后,从每一组数据项的内部来看,数据项的顺序保持不变;这趟排序必须是稳定。
④ 然后再把10组数据项重新合并,排在最前面的是十位上为0的数据项,然后是十位为1的数据项,如此排序到十位上为9的数据项
⑤ 对剩余位重复这个过程。如果某些数据项的位数少于其他数据项的,那么认为他们的最高位为0
排序测试代码:
插入排序
1.直接插入排序
原理:将数组分为无序区和有序区两个区,然后不断将无序区的第一个元素按大小顺序插入到有序区中去,最终将所有无序区元素都移动到有序区完成排序。
要点:设立哨兵,作为临时存储和判断数组边界之用。
实现:
Void InsertSort(Node L[],int length)
{
Int i,j;//分别为有序区和无序区指针
for(i=1;i<length;i++)//逐步扩大有序区
{
j=i+1;
if(L[j]<L[i])
{
L[0]=L[j];//存储待排序元素
While(L[0]<L[i])//查找在有序区中的插入位置,同时移动元素
{
L[i+1]=L[i];//移动
i--;//查找
}
L[i+1]=L[0];//将元素插入
}
i=j-1;//还原有序区指针
}
}
2.希尔排序
原理:又称增量缩小排序。先将序列按增量划分为元素个数相同的若干组,使用直接插入排序法进行排序,然后不断缩小增量直至为1,最后使用直接插入排序完成排序。
要点:增量的选择以及排序最终以1为增量进行排序结束。
实现:
Void shellSort(Node L[],int d)
{
While(d>=1)//直到增量缩小为1
{
Shell(L,d);
d=d/2;//缩小增量
}
}
Void Shell(Node L[],int d)
{
Int i,j;
For(i=d+1;i<length;i++)
{
if(L[i]<L[i-d])
{
L[0]=L[i];
j=i-d;
While(j>0&&L[j]>L[0])
{
L[j+d]=L[j];//移动
j=j-d;//查找
}
L[j+d]=L[0];
}
}
}
交换排序
1.冒泡排序
原理:将序列划分为无序和有序区,不断通过交换较大元素至无序区尾完成排序。
要点:设计交换判断条件,提前结束以排好序的序列循环。
实现:
Void BubbleSort(Node L[])
{
Int i ,j;
Bool ischanged;//设计跳出条件
For(j=n;j<0;j--)
{
ischanged =false;
For(i=0;i<j;i++)
{
If(L[i]>L[i+1])//如果发现较重元素就向后移动
{
Int temp=L[i];
L[i]=L[i+1];
L[i+1]=temp;
Ischanged =true;
}
}
If(!ischanged)//若没有移动则说明序列已经有序,直接跳出
Break;
}
}
2.快速排序
原理:不断寻找一个序列的中点,然后对中点左右的序列递归的进行排序,直至全部序列排序完成,使用了分治的思想。
要点:递归、分治
实现:
选择排序
1.直接选择排序
原理:将序列划分为无序和有序区,寻找无序区中的最小值和无序区的首元素交换,有序区扩大一个,循环最终完成全部排序。
要点:
实现:
Void SelectSort(Node L[])
{
Int i,j,k;//分别为有序区,无序区,无序区最小元素指针
For(i=0;i<length;i++)
{
k=i;
For(j=i+1;j<length;j++)
{
If(L[j]<L[k])
k=j;
}
If(k!=i)//若发现最小元素,则移动到有序区
{
Int temp=L[k];
L[k]=L[i];
L[i]=L[temp];
}
}
}
2.堆排序
原理:利用大根堆或小根堆思想,首先建立堆,然后将堆首与堆尾交换,堆尾之后为有序区。
要点:建堆、交换、调整堆
实现:
Void HeapSort(Node L[])
{
BuildingHeap(L);//建堆(大根堆)
For(int i=n;i>0;i--)//交换
{
Int temp=L[i];
L[i]=L[0];
L[0]=temp;
Heapify(L,0,i);//调整堆
}
}
Void BuildingHeap(Node L[])
{ For(i=length/2 -1;i>0;i--)
Heapify(L,i,length);
}
归并排序
原理:将原序列划分为有序的两个序列,然后利用归并算法进行合并,合并之后即为有序序列。
要点:归并、分治
实现:
Void MergeSort(Node L[],int m,int n)
{
Int k;
If(m<n)
{
K=(m+n)/2;
MergeSort(L,m,k);
MergeSort(L,k+1,n);
Merge(L,m,k,n);
}
}
基数排序
原理:将数字按位数划分出n个关键字,每次针对一个关键字进行排序,然后针对排序后的序列进行下一个关键字的排序,循环至所有关键字都使用过则排序完成。
要点:对关键字的选取,元素分配收集。
实现:
Void RadixSort(Node L[],length,maxradix)
{
Int m,n,k,lsp;
k=1;m=1;
Int temp[10][length-1];
Empty(temp); //清空临时空间
While(k<maxradix) //遍历所有关键字
{
For(int i=0;i<length;i++) //分配过程
{
If(L[i]<m)
Temp[0]
=L[i];
Else
Lsp=(L[i]/m)%10; //确定关键字
Temp[lsp]
=L[i];
n++;
}
CollectElement(L,Temp); //收集
n=0;
m=m*10;
k++;
}
}
http://blog.163.com/jiang-640/blog/static/8640359420092192225711/
可以参考:
1、 插入排序
比较和交换的时间复杂度为O(n^2),算法自适应,对于数据已基本有序的情况,时间复杂度为O(n),算法稳定,开销很低,适合于数据已基本有序或者数据量小的情况。
public void insertionSort() {// 插入排序 int out, in; int count1 = 0, count2 = 0;// 复制次数,比较次数 for (out = 1; out < nElems; out++) { long temp = a[out]; in = out; boolean flag=in>0&&a[in-1]>=temp; while(flag){ if(a[in-1]>=temp){ if(in>0){ a[in]=a[in-1]; count1++; --in; } } count2++; flag=in>0&&a[in-1]>=temp; } a[in] = temp; } System.out.println("复制次数为:" + count1 + " 比较次数为:" + count2); }
2、 选择排序
算法不稳定,O(1)的额外的空间,比较的时间复杂度为O(n^2),交换的时间复杂度为O(n),并不是自适应的。在大多数情况下都不推荐使用。只有在希望减少交换次数的情况下可以用。
public void selectionSort(){//选择排序 int out, in, min; for(out=0;out<nElems-1;out++){ min=out; for(in=out+1;in<nElems;in++){ if(a[in]<a[min]){ min=in; } swap(out,min); } } }
3、 冒泡排序
算法稳定,O(1)的额外的空间,比较和交换的时间复杂度都是O(n^2),自适应,对于已基本排序的算法,时间复杂度为O(n)。冒泡算法的许多性质和插入算法相似,但对于系统开销高一点点。
public void bubbleSort() {// 冒泡排序,单项 int out, in; for (out = nElems - 1; out > 1; out--) { for (in = 0; in < out; in++) { if (a[in] > a[in + 1]) { swap(in, in + 1); } } } }
4、 希尔排序
希尔排序并不稳定,O(1)的额外空间,时间复杂度为O(N*(logN)^2)。这中算法是基于插入排序的。最坏的情况下的执行效率和在平均情况下的执行效率相比相差不多。
public void shellSort(){ int inner, outer; long temp; int h=1; while(h<nElems/3){ h=h*3+1; }//Knuth序列初始化 while(h>0){ for(outer=h;outer<nElems;outer++){ temp = theArray[outer]; inner = outer; while((inner>h-1)&&theArray[inner-h]>=temp){ theArray[inner]=theArray[inner]; inner-=h; } theArray[inner]=temp; } h=(h-1)/3; } }
5、 归并排序
归并算法稳定,数组需要O(n)的额外空间,链表需要O(log(n))的额外空间,时间复杂度为O(nlog(n)),算法不是自适应的,不需要对数据的随机读取。
public void mergeSort(){ long[] workSpace = new long[nElems]; recMergeSort(workSpace,0,nElems-1); } private void recMergeSort(long[] workSpace, int lowerBound, int upperBound){ if(lowerBound == upperBound){ return; } else{ int mid=(lowerBound+upperBound)/2; recMergeSort(workSpace, lowerBound, mid); recMergeSort(workSpace, mid+1, upperBound); merge(workSpace, lowerBound, mid+1, upperBound); } } private void merge(long[] workSpace, int lowPtr, int highPtr, int upperBound){ int j = 0; int lowerBound = lowPtr; int mid = highPtr - 1; int n = upperBound-lowerBound+1; while(lowPtr<=mid&&highPtr<=upperBound){ if(theArray[lowPtr]<theArray[highPtr]){ workSpace[j++]=theArray[lowPtr++]; } else{ workSpace[j++]=theArray[highPtr++]; } } while(lowPtr<=mid){ workSpace[j++] = theArray[lowPtr++]; } while(highPtr<=upperBound){ workSpace[j++] = theArray[highPtr++]; } for(j=0;j<n;j++){ theArray[lowerBound+j]=workSpace[j]; } }
6、java堆排序的实现
import java.io.IOException; class MyNode { private int iData; public MyNode(int key) { iData = key; } public int getKey() { return iData; } } public class Heap { private MyNode[] heapArray; private int maxSize; private int currentSize; // number of items in array public Heap(int mx) { maxSize = mx; currentSize = 0; heapArray = new MyNode[maxSize]; } public MyNode remove() { MyNode root = heapArray[0]; heapArray[0] = heapArray[--currentSize]; trickleDown(0); return root; } public void trickleDown(int index) { int largerChild; MyNode top = heapArray[index]; while (index < currentSize / 2) { int leftChild = 2 * index + 1; int rightChild = leftChild + 1; // 找到最大的子节点 if (rightChild < currentSize && heapArray[leftChild].getKey() < heapArray[rightChild] .getKey()) largerChild = rightChild; else largerChild = leftChild; if (top.getKey() >= heapArray[largerChild].getKey()) break; heapArray[index] = heapArray[largerChild]; index = largerChild; } heapArray[index] = top; } public void displayHeap() { int nBlanks = 32; int itemsPerRow = 1; int column = 0; int currentIndex = 0; while (currentSize > 0) { if (column == 0) for (int k = 0; k < nBlanks; k++) System.out.print(' '); System.out.print(heapArray[currentIndex].getKey()); if (++currentIndex == currentSize) // 判断是否输出结束 break; if (++column == itemsPerRow) // 是否到达行尾? { nBlanks /= 2; itemsPerRow *= 2; column = 0; System.out.println(); } else for (int k = 0; k < nBlanks * 2 - 2; k++) System.out.print(' '); // 输入空白 } } public void displayArray() { for (int j = 0; j < maxSize; j++) System.out.print(heapArray[j].getKey() + " "); System.out.println(""); } public void insertAt(int index, MyNode newNode) { heapArray[index] = newNode; } public void incrementSize() { currentSize++; } public static void main(String[] args) throws IOException { int size, i; size = 100; Heap theHeap = new Heap(size); for (i = 0; i < size; i++) { int random = (int) (java.lang.Math.random() * 100); MyNode newNode = new MyNode(random); theHeap.insertAt(i, newNode); theHeap.incrementSize(); } System.out.print("Random: "); theHeap.displayArray(); for (i = size / 2 - 1; i >= 0; i--) theHeap.trickleDown(i); System.out.print("Heap: "); theHeap.displayArray(); theHeap.displayHeap(); for (i = size - 1; i >= 0; i--) { MyNode biggestNode = theHeap.remove(); theHeap.insertAt(i, biggestNode); } System.out.print("Sorted: "); theHeap.displayArray(); } }
7、 快速排序
快速排序不稳定,O(log(n))的额外空间,时间复杂度为O(nlog(n)),不是自适应的。
public void quickSort(){ recQuickSort(0,nElems-1); } public void recQuickSort(int left, int right){ if(right-left<=0){ return; }else{ long pivot = theArray[right]; int partition = partitionIt(left, right, pivot); recQuickSort(left, partition-1); recQuickSort(partition+1, right); } } public int partitionIt(int left, int right, long pivot){ int leftPtr = left -1; int rightPtr = right; while(true){ while(theArray[++leftPtr]<pivot); while(rightPtr>0&&theArray[--rightPtr]>pivot); if(leftPtr>=rightPtr){ break; }else{ swap(leftPtr,rightPtr); } }swap(leftPtr,right); return leftPtr; } public void swap(int dex1, int dex2){ long temp; temp = theArray[dex1]; theArray[dex1]=theArray[dex2]; theArray[dex2]=temp; }
8、 基数排序
以基数是10为例
① 根据数据项个位上的值,把所有的数据分为10组。
② 然后对这10组数据项重新排列:把所有关键字是以0结尾的数据排在最后面,然后是关键字结尾时1的数据项,照此顺序直到以9结尾的数据项。这个步骤被称为第一趟子排序。
③ 在第二趟子排序中,再次把所有的数据项分为10组,但是这一次是根据数据项十位上的值来分组。这次分组不能改变先前的排序顺序。也就是说,第二趟排序之后,从每一组数据项的内部来看,数据项的顺序保持不变;这趟排序必须是稳定。
④ 然后再把10组数据项重新合并,排在最前面的是十位上为0的数据项,然后是十位为1的数据项,如此排序到十位上为9的数据项
⑤ 对剩余位重复这个过程。如果某些数据项的位数少于其他数据项的,那么认为他们的最高位为0
public static int[] countSort(int[] a, int k) { int[] b = new int[a.length]; int[] c = new int[10]; for (int i = 0; i < b.length; i++) { b[i] = 0; } for (int i = 0; i < c.length; i++) { c[i] = 0; } int s = 1; for (int i = 0; i < k; i++) { s = s * 10; } int temp1 = 0; for (int i = 0; i < a.length; i++) { temp1 = a[i] % s; temp1 = temp1 * 10 / s; c[temp1] = c[temp1] + 1; } for (int i = 1; i < c.length; i++) { c[i] = c[i] + c[i - 1]; } int temp2 = 0; for (int i = a.length - 1; i >= 0; i--) { temp1 = a[i]; temp2 = a[i] % s; temp2 = temp2 * 10 / s; b[c[temp2] - 1] = temp1; c[temp2] = c[temp2] - 1; } return b; }
排序测试代码:
package com.softeem.jbs.lesson4; import java.util.Random; /** * 排序测试类 * * 排序算法的分类如下: * 1.插入排序(直接插入排序、折半插入排序、希尔排序); * 2.交换排序(冒泡泡排序、快速排序); * 3.选择排序(直接选择排序、堆排序); * 4.归并排序; * 5.基数排序。 * * 关于排序方法的选择: * (1)若n较小(如n≤50),可采用直接插入或直接选择排序。 * 当记录规模较小时,直接插入排序较好;否则因为直接选择移动的记录数少于直接插人,应选直接选择排序为宜。 * (2)若文件初始状态基本有序(指正序),则应选用直接插人、冒泡或随机的快速排序为宜; * (3)若n较大,则应采用时间复杂度为O(nlgn)的排序方法:快速排序、堆排序或归并排序。 * */ public class SortTest { /** * 初始化测试数组的方法 * @return 一个初始化好的数组 */ public int[] createArray() { Random random = new Random(); int[] array = new int[10]; for (int i = 0; i < 10; i++) { array[i] = random.nextInt(100) - random.nextInt(100);//生成两个随机数相减,保证生成的数中有负数 } System.out.println("==========原始序列=========="); printArray(array); return array; } /** * 打印数组中的元素到控制台 * @param source */ public void printArray(int[] data) { for (int i : data) { System.out.print(i + " "); } System.out.println(); } /** * 交换数组中指定的两元素的位置 * @param data * @param x * @param y */ private void swap(int[] data, int x, int y) { int temp = data[x]; data[x] = data[y]; data[y] = temp; } /** * 冒泡排序----交换排序的一种 * 方法:相邻两元素进行比较,如有需要则进行交换,每完成一次循环就将最大元素排在最后(如从小到大排序),下一次循环是将其他的数进行类似操作。 * 性能:比较次数O(n^2),n^2/2;交换次数O(n^2),n^2/4 * * @param data 要排序的数组 * @param sortType 排序类型 * @return */ public void bubbleSort(int[] data, String sortType) { if (sortType.equals("asc")) { //正排序,从小排到大 //比较的轮数 for (int i = 1; i < data.length; i++) { //将相邻两个数进行比较,较大的数往后冒泡 for (int j = 0; j < data.length - i; j++) { if (data[j] > data[j + 1]) { //交换相邻两个数 swap(data, j, j + 1); } } } } else if (sortType.equals("desc")) { //倒排序,从大排到小 //比较的轮数 for (int i = 1; i < data.length; i++) { //将相邻两个数进行比较,较大的数往后冒泡 for (int j = 0; j < data.length - i; j++) { if (data[j] < data[j + 1]) { //交换相邻两个数 swap(data, j, j + 1); } } } } else { System.out.println("您输入的排序类型错误!"); } printArray(data);//输出冒泡排序后的数组值 } /** * 直接选择排序法----选择排序的一种 * 方法:每一趟从待排序的数据元素中选出最小(或最大)的一个元素, 顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。 * 性能:比较次数O(n^2),n^2/2 * 交换次数O(n),n * 交换次数比冒泡排序少多了,由于交换所需CPU时间比比较所需的CUP时间多,所以选择排序比冒泡排序快。 * 但是N比较大时,比较所需的CPU时间占主要地位,所以这时的性能和冒泡排序差不太多,但毫无疑问肯定要快些。 * * @param data 要排序的数组 * @param sortType 排序类型 * @return */ public void selectSort(int[] data, String sortType) { if (sortType.equals("asc")) { //正排序,从小排到大 int index; for (int i = 1; i < data.length; i++) { index = 0; for (int j = 1; j <= data.length - i; j++) { if (data[j] > data[index]) { index = j; } } //交换在位置data.length-i和index(最大值)两个数 swap(data, data.length - i, index); } } else if (sortType.equals("desc")) { //倒排序,从大排到小 int index; for (int i = 1; i < data.length; i++) { index = 0; for (int j = 1; j <= data.length - i; j++) { if (data[j] < data[index]) { index = j; } } //交换在位置data.length-i和index(最大值)两个数 swap(data, data.length - i, index); } } else { System.out.println("您输入的排序类型错误!"); } printArray(data);//输出直接选择排序后的数组值 } /** * 插入排序 * 方法:将一个记录插入到已排好序的有序表(有可能是空表)中,从而得到一个新的记录数增1的有序表。 * 性能:比较次数O(n^2),n^2/4 * 复制次数O(n),n^2/4 * 比较次数是前两者的一般,而复制所需的CPU时间较交换少,所以性能上比冒泡排序提高一倍多,而比选择排序也要快。 * * @param data 要排序的数组 * @param sortType 排序类型 */ public void insertSort(int[] data, String sortType) { if (sortType.equals("asc")) { //正排序,从小排到大 //比较的轮数 for (int i = 1; i < data.length; i++) { //保证前i+1个数排好序 for (int j = 0; j < i; j++) { if (data[j] > data[i]) { //交换在位置j和i两个数 swap(data, i, j); } } } } else if (sortType.equals("desc")) { //倒排序,从大排到小 //比较的轮数 for (int i = 1; i < data.length; i++) { //保证前i+1个数排好序 for (int j = 0; j < i; j++) { if (data[j] < data[i]) { //交换在位置j和i两个数 swap(data, i, j); } } } } else { System.out.println("您输入的排序类型错误!"); } printArray(data);//输出插入排序后的数组值 } /** * 反转数组的方法 * @param data 源数组 */ public void reverse(int[] data) { int length = data.length; int temp = 0;//临时变量 for (int i = 0; i < length / 2; i++) { temp = data[i]; data[i] = data[length - 1 - i]; data[length - 1 - i] = temp; } printArray(data);//输出到转后数组的值 } /** * 快速排序 * 快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为两个子序列(sub-lists)。 * 步骤为: * 1. 从数列中挑出一个元素,称为 "基准"(pivot), * 2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分割之后,该基准是它的最后位置。这个称为分割(partition)操作。 * 3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。 * 递回的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递回下去,但是这个算法总会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。 * @param data 待排序的数组 * @param low * @param high * @see SortTest#qsort(int[], int, int) * @see SortTest#qsort_desc(int[], int, int) */ public void quickSort(int[] data, String sortType) { if (sortType.equals("asc")) { //正排序,从小排到大 qsort_asc(data, 0, data.length - 1); } else if (sortType.equals("desc")) { //倒排序,从大排到小 qsort_desc(data, 0, data.length - 1); } else { System.out.println("您输入的排序类型错误!"); } } /** * 快速排序的具体实现,排正序 * @param data * @param low * @param high */ private void qsort_asc(int data[], int low, int high) { int i, j, x; if (low < high) { //这个条件用来结束递归 i = low; j = high; x = data[i]; while (i < j) { while (i < j && data[j] > x) { j--; //从右向左找第一个小于x的数 } if (i < j) { data[i] = data[j]; i++; } while (i < j && data[i] < x) { i++; //从左向右找第一个大于x的数 } if (i < j) { data[j] = data[i]; j--; } } data[i] = x; qsort_asc(data, low, i - 1); qsort_asc(data, i + 1, high); } } /** * 快速排序的具体实现,排倒序 * @param data * @param low * @param high */ private void qsort_desc(int data[], int low, int high) { int i, j, x; if (low < high) { //这个条件用来结束递归 i = low; j = high; x = data[i]; while (i < j) { while (i < j && data[j] < x) { j--; //从右向左找第一个小于x的数 } if (i < j) { data[i] = data[j]; i++; } while (i < j && data[i] > x) { i++; //从左向右找第一个大于x的数 } if (i < j) { data[j] = data[i]; j--; } } data[i] = x; qsort_desc(data, low, i - 1); qsort_desc(data, i + 1, high); } } /** *二分查找特定整数在整型数组中的位置(递归) *查找线性表必须是有序列表 *@paramdataset *@paramdata *@parambeginIndex *@paramendIndex *@returnindex */ public int binarySearch(int[] dataset, int data, int beginIndex, int endIndex) { int midIndex = (beginIndex + endIndex) >>> 1; //相当于mid = (low + high) / 2,但是效率会高些 if (data < dataset[beginIndex] || data > dataset[endIndex] || beginIndex > endIndex) return -1; if (data < dataset[midIndex]) { return binarySearch(dataset, data, beginIndex, midIndex - 1); } else if (data > dataset[midIndex]) { return binarySearch(dataset, data, midIndex + 1, endIndex); } else { return midIndex; } } /** *二分查找特定整数在整型数组中的位置(非递归) *查找线性表必须是有序列表 *@paramdataset *@paramdata *@returnindex */ public int binarySearch(int[] dataset, int data) { int beginIndex = 0; int endIndex = dataset.length - 1; int midIndex = -1; if (data < dataset[beginIndex] || data > dataset[endIndex] || beginIndex > endIndex) return -1; while (beginIndex <= endIndex) { midIndex = (beginIndex + endIndex) >>> 1; //相当于midIndex = (beginIndex + endIndex) / 2,但是效率会高些 if (data < dataset[midIndex]) { endIndex = midIndex - 1; } else if (data > dataset[midIndex]) { beginIndex = midIndex + 1; } else { return midIndex; } } return -1; } public static void main(String[] args) { SortTest sortTest = new SortTest(); int[] array = sortTest.createArray(); System.out.println("==========冒泡排序后(正序)=========="); sortTest.bubbleSort(array, "asc"); System.out.println("==========冒泡排序后(倒序)=========="); sortTest.bubbleSort(array, "desc"); array = sortTest.createArray(); System.out.println("==========倒转数组后=========="); sortTest.reverse(array); array = sortTest.createArray(); System.out.println("==========选择排序后(正序)=========="); sortTest.selectSort(array, "asc"); System.out.println("==========选择排序后(倒序)=========="); sortTest.selectSort(array, "desc"); array = sortTest.createArray(); System.out.println("==========插入排序后(正序)=========="); sortTest.insertSort(array, "asc"); System.out.println("==========插入排序后(倒序)=========="); sortTest.insertSort(array, "desc"); array = sortTest.createArray(); System.out.println("==========快速排序后(正序)=========="); sortTest.quickSort(array, "asc"); sortTest.printArray(array); System.out.println("==========快速排序后(倒序)=========="); sortTest.quickSort(array, "desc"); sortTest.printArray(array); System.out.println("==========数组二分查找=========="); System.out.println("您要找的数在第" + sortTest.binarySearch(array, 74) + "个位子。(下标从0计算)"); } }
插入排序
1.直接插入排序
原理:将数组分为无序区和有序区两个区,然后不断将无序区的第一个元素按大小顺序插入到有序区中去,最终将所有无序区元素都移动到有序区完成排序。
要点:设立哨兵,作为临时存储和判断数组边界之用。
实现:
Void InsertSort(Node L[],int length)
{
Int i,j;//分别为有序区和无序区指针
for(i=1;i<length;i++)//逐步扩大有序区
{
j=i+1;
if(L[j]<L[i])
{
L[0]=L[j];//存储待排序元素
While(L[0]<L[i])//查找在有序区中的插入位置,同时移动元素
{
L[i+1]=L[i];//移动
i--;//查找
}
L[i+1]=L[0];//将元素插入
}
i=j-1;//还原有序区指针
}
}
2.希尔排序
原理:又称增量缩小排序。先将序列按增量划分为元素个数相同的若干组,使用直接插入排序法进行排序,然后不断缩小增量直至为1,最后使用直接插入排序完成排序。
要点:增量的选择以及排序最终以1为增量进行排序结束。
实现:
Void shellSort(Node L[],int d)
{
While(d>=1)//直到增量缩小为1
{
Shell(L,d);
d=d/2;//缩小增量
}
}
Void Shell(Node L[],int d)
{
Int i,j;
For(i=d+1;i<length;i++)
{
if(L[i]<L[i-d])
{
L[0]=L[i];
j=i-d;
While(j>0&&L[j]>L[0])
{
L[j+d]=L[j];//移动
j=j-d;//查找
}
L[j+d]=L[0];
}
}
}
交换排序
1.冒泡排序
原理:将序列划分为无序和有序区,不断通过交换较大元素至无序区尾完成排序。
要点:设计交换判断条件,提前结束以排好序的序列循环。
实现:
Void BubbleSort(Node L[])
{
Int i ,j;
Bool ischanged;//设计跳出条件
For(j=n;j<0;j--)
{
ischanged =false;
For(i=0;i<j;i++)
{
If(L[i]>L[i+1])//如果发现较重元素就向后移动
{
Int temp=L[i];
L[i]=L[i+1];
L[i+1]=temp;
Ischanged =true;
}
}
If(!ischanged)//若没有移动则说明序列已经有序,直接跳出
Break;
}
}
2.快速排序
原理:不断寻找一个序列的中点,然后对中点左右的序列递归的进行排序,直至全部序列排序完成,使用了分治的思想。
要点:递归、分治
实现:
选择排序
1.直接选择排序
原理:将序列划分为无序和有序区,寻找无序区中的最小值和无序区的首元素交换,有序区扩大一个,循环最终完成全部排序。
要点:
实现:
Void SelectSort(Node L[])
{
Int i,j,k;//分别为有序区,无序区,无序区最小元素指针
For(i=0;i<length;i++)
{
k=i;
For(j=i+1;j<length;j++)
{
If(L[j]<L[k])
k=j;
}
If(k!=i)//若发现最小元素,则移动到有序区
{
Int temp=L[k];
L[k]=L[i];
L[i]=L[temp];
}
}
}
2.堆排序
原理:利用大根堆或小根堆思想,首先建立堆,然后将堆首与堆尾交换,堆尾之后为有序区。
要点:建堆、交换、调整堆
实现:
Void HeapSort(Node L[])
{
BuildingHeap(L);//建堆(大根堆)
For(int i=n;i>0;i--)//交换
{
Int temp=L[i];
L[i]=L[0];
L[0]=temp;
Heapify(L,0,i);//调整堆
}
}
Void BuildingHeap(Node L[])
{ For(i=length/2 -1;i>0;i--)
Heapify(L,i,length);
}
归并排序
原理:将原序列划分为有序的两个序列,然后利用归并算法进行合并,合并之后即为有序序列。
要点:归并、分治
实现:
Void MergeSort(Node L[],int m,int n)
{
Int k;
If(m<n)
{
K=(m+n)/2;
MergeSort(L,m,k);
MergeSort(L,k+1,n);
Merge(L,m,k,n);
}
}
基数排序
原理:将数字按位数划分出n个关键字,每次针对一个关键字进行排序,然后针对排序后的序列进行下一个关键字的排序,循环至所有关键字都使用过则排序完成。
要点:对关键字的选取,元素分配收集。
实现:
Void RadixSort(Node L[],length,maxradix)
{
Int m,n,k,lsp;
k=1;m=1;
Int temp[10][length-1];
Empty(temp); //清空临时空间
While(k<maxradix) //遍历所有关键字
{
For(int i=0;i<length;i++) //分配过程
{
If(L[i]<m)
Temp[0]
=L[i];
Else
Lsp=(L[i]/m)%10; //确定关键字
Temp[lsp]
=L[i];
n++;
}
CollectElement(L,Temp); //收集
n=0;
m=m*10;
k++;
}
}
http://blog.163.com/jiang-640/blog/static/8640359420092192225711/
可以参考:
相关文章推荐
- 基于JAVA的排序算法之十--几种排序…
- Java数组几种排序
- Java实现几种常见排序方法
- java的几种常用的排序
- Java实现几种常见排序方法(上)
- Java原来如此-几种常见的排序--冒泡排序(Bubble Sort)
- 学Java的必知几种排序(终极秘籍)
- Java实现几种常见排序方法
- Java中的几种排序算法:冒泡排序,插入排序,二分法排序,简单排序,快速排序
- Java实现几种常见排序方法
- java几种排序简单实现(快速排序,冒泡排序,直接插入排序)
- (转)java的几种排序方法
- 几种排序小结 JAVA语言描述
- java 数组常见的几种排序
- JAVA 中数组的几种排序方法
- 几种基本排序的java实现
- Java中几种常见的排序方式
- Java实现几种常见排序方法
- Java实现几种常见排序方法
- java 几种排序