近期看了下数据结构,顺便查看了里面一些排序算法的实现,下面是转载别人的,我也都实现了下,有很多的方法可以单独成一个工具类,但为了简单就重复了,包涵!
package sort;
public class ShellSort {
/**
* Shell排序是不稳定的,它的空间开销也是O(1),时间开销估计在O(N3/2)~O(N7/6)之间
* 和直接插入法比较,会发现其与直接插入排序的差别在于:直接插入排序中的h会以1代替
* 在排序的数据基本有序,shell有很大的优势
* 希尔排序的增量只要保证最后一次是1就行
* @author ps
* 2012-7-19 上午06:58:10
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] data = new int[] { 9, 3, 6, 2, 1, 5, 4, 8, 7 };
// int[] data = new int[] { 9, 1, 5, 4, 8, 7 };
// int[] data = new int[] { 25, 85, 56, 92, 11, 49, 38, 7 };
print(data);
shellSort(data);
System.out.println("排序后的数组:");
print(data);
}
private static void shellSort(int[] data) {
// TODO Auto-generated method stub
// 计算出最大的h值
int h = 1;
while (h <= data.length / 3) {
h = h * 3 + 1;
}
while (h > 0) {
System.out.println(h+"-------------");
for (int i = h; i < data.length; i ++) {
if (data[i] < data[i - h]) {
int tmp = data[i];
int j = i - h;
while (j >= 0 && data[j] > tmp) {
data[j + h] = data[j];
j -= h;
}
data[j + h] = tmp;
print(data);
}
}
// 计算出下一个h值
h = (h - 1)/3;
}
}
private static void print(int[] data) {
// TODO Auto-generated method stub
for (int i = 0; i < data.length; i++) {
System.out.print(data[i] + "\t");
}
System.out.println();
}
}
package sort;
public class BinaryInsertSort {
/**
* 折半插入排序法,又称二分插入排序法,是直接插入排序法的改良版,也需要执行i-1趟插入,假定前i个数据是已经处于有序状态
* @author ps
* 2012-7-19 上午06:13:07
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
// int[] data = new int[] { 5, 3, 6, 2, 1, 9, 4, 8, 7 };
int[] data = new int[] { 25, 85, 56, 92, 11, 49, 38, 7 };
print(data);
binaryInsertSort(data);
System.out.println("排序后的数组:");
print(data);
}
private static void binaryInsertSort(int[] data) {
// TODO Auto-generated method stub
int start, end, mid,temp;
for(int i=1;i<data.length;i++){
if(data[i]<data[i-1]){
temp = data[i];
start = 0;
end = i-1;
while(start<=end){
mid = (start+end)/2;
if(data[mid]<temp){
start = mid+1;
}else{
end = mid-1;
}
}
for(int j=i;j>start;j--){
data[j] = data[j-1];
}
data[start] = temp;
print(data);
}
}
}
private static void print(int[] data) {
// TODO Auto-generated method stub
for (int i = 0; i < data.length; i++) {
System.out.print(data[i] + "\t");
}
System.out.println();
}
}
package sort;
public class BubbleSort {
/**
* 它的时间复杂度为O(n^2),虽然不及堆排序、快速排序的O(nlogn,底数为2),但是有两个优点:
* 1.“编程复杂度”很低,很容易写出代码
* 2.具有稳定性,这里的稳定性是指原序列中相同元素的相对顺序仍然保持到排序后的序列,而堆排序、快速排序均不具有稳定性。
* 不过,一路、二路归并排序、不平衡二叉树排序的速度均比冒泡排序快,且具有稳定性,但速度不及堆排序、快速排序。
* 冒泡排序是经过n-1趟子排序完成的,第i趟子排序从第1个数至第n-i个数,若第i个数比后一个数大(则升序,小则降序)则交换两数。
* 冒泡排序算法稳定,O(1)的额外的空间,比较和交换的时间复杂度都是O(n^2),自适应,对于已基本排序的算法,时间复杂度为O(n)。
* 冒泡算法的许多性质和插入算法相似,但对于系统开销高一点点
* @author ps
* 2012-7-19 上午02:27:15
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] data = new int[] { 5, 3, 6, 2, 1, 9, 4, 8, 7};
print(data);
bubbleSort(data);
System.out.println("排序后的数组:");
print(data);
}
private static void bubbleSort(int[] data) {
// TODO Auto-generated method stub
for(int i=0;i<data.length-1;i++){
boolean flag = false;
for(int j=0;j<data.length-i-1;j++){
if(data[j]<data[j+1]){//<是降序,>是升序
swap(data,j,j+1);
flag = true;
}
}
if(flag)
print(data);
}
}
private static void swap(int[] data, int j, int i) {
// TODO Auto-generated method stub
if (i == j) {
return;
}
data[i] = data[i] + data[j];
data[j] = data[i] - data[j];
data[i] = data[i] - data[j];
}
private static void print(int[] data) {
// TODO Auto-generated method stub
for (int i = 0; i < data.length; i++) {
System.out.print(data[i] + "\t");
}
System.out.println();
}
}
package sort;
/**
* 堆排序是不稳定的排序方法,辅助空间为O(1), 最坏时间复杂度为O(nlog2n) ,
* 堆排序的堆序的平均性能较接近于最坏性能。
* @author ps
* 2012-7-19 上午02:22:03
*/
public class Heapsort {
public static void main(String[] args) {
int[] data = new int[] { 5, 3, 6, 2, 1, 9, 4, 8, 7 };
// int[] data = new int[] { 25, 85, 56, 92, 11, 49, 38, 7 };
print(data);
heapSort(data);
System.out.println("排序后的数组:");
print(data);
}
public static 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];
}
public static void heapSort(int[] data) {
for (int i = 0; i < data.length; i++) {
// createMaxdHeap(data, data.length - 1 - i);
createMinHeap(data, data.length - 1 - i);
print(data);//打印堆
swap(data, 0, data.length - 1 - i);
print(data);
}
}
/**
* 大根堆
* @author ps
* 2012-7-19 上午01:46:30
* @param data
* @param lastIndex
*/
public static void createMaxdHeap(int[] data, int lastIndex) {
for (int i = (lastIndex - 1) / 2; i >= 0; i--) {
// 保存当前正在判断的节点
int k = i;
// 若当前节点的子节点存在
while (2 * k + 1 <= lastIndex) {
// biggerIndex总是记录较大节点的值,先赋值为当前判断节点的左子节点
int biggerIndex = 2 * k + 1;//左节点
if (biggerIndex < lastIndex) {// 若右子节点存在,
if (data[biggerIndex] < data[biggerIndex + 1]) {//左右节点大小
// 若右子节点值比左子节点值大,则biggerIndex记录的是右子节点的值
biggerIndex = 2 * k + 2;//或者用这个biggerIndex++;表示右节点
}
}
if (data[k] < data[biggerIndex]) {//和父节点比较
// 若当前节点值比子节点最大值小,则交换2者得值,交换后将biggerIndex值赋值给k
swap(data, k, biggerIndex);
k = biggerIndex;
} else {
break;
}
}
}
}
/**
* 小根堆
* @author ps
* 2012-7-19 上午01:47:26
* @param data
* @param lastIndex
*/
public static void createMinHeap(int[] data, int lastIndex) {
for(int i = (lastIndex-1)/2;i>=0;i--){
int k = i;//父节点
while((2*k+1)<=lastIndex){
int minIndex = 2*k+1;
if(minIndex<lastIndex){//判断是否存在右节点
if(data[minIndex]>data[minIndex+1]){//比较左右节点大小
minIndex ++;
}
}
if(data[k]>data[minIndex]){
swap(data,k,minIndex);
k = minIndex;
}else{
break;
}
}
}
}
public static void print(int[] data) {
for (int i = 0; i < data.length; i++) {
System.out.print(data[i] + "\t");
}
System.out.println();
}
}
package sort;
/**
* 直接插入的时间效率并不高,如果在最坏的情况下,所有元素的比较次数总和为(0+1+...+n-1)=O(n^2)。其他情况下也要考虑移动元素的次数,故时间复杂度为O(n^2)
* 直接插入空间效率很好,只需要1个缓存数据单元,也就是说空间复杂度为O(1).
* 直接插入排序是稳定的。
* 直接插入排序在数据已有一定顺序的情况下,效率较好。但如果数据无规则,则需要移动大量的数据,其效率就与冒泡排序法和选择排序法一样差了。
* @author ps
* 2012-7-19 上午02:23:46
*/
public class InsertSort {
/**
* @param args
* 直接插入排序
* 稳定的排序方法
*/
public static void main(String[] args) {
int[] data = new int[] { 5, 3, 6, 2, 1, 9, 4, 8, 7 };
print(data);
insertSort(data);
System.out.println("排序后的数组:");
print(data);
}
private static void insertSort(int[] data) {
int temp,j;
for(int i=1;i<data.length;i++){
temp = data[i];
if(data[i]<data[i-1]){
j = i-1;
while(j>=0 && data[j]>temp){
data[j+1] = data[j];
j--;
}
data[j+1] = temp;
print(data);
}
}
}
private static void print(int[] data) {
for(int i=0;i<data.length;i++){
System.out.print(data[i]+"\t");
}
System.out.println();
}
}
package sort;
/*
归并排序(Merge)是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。 将已有序的子序列合并,得到完全有序的序列;
即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。
归并排序算法稳定,数组需要O(n)的额外空间,链表需要O(log(n))的额外空间,时间复杂度为O(nlog(n)),算法不是自适应的,不需要对数据的随机读取。
工作原理:
1、申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
2、设定两个指针,最初位置分别为两个已经排序序列的起始位置
3、比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
4、重复步骤3直到某一指针达到序列尾
5、将另一序列剩下的所有元素直接复制到合并序列尾
*/
public class MergeSort {
/**
* @author ps
* 2012-7-20 上午01:38:07
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] data = new int[] { 5, 3, 6, 2, 1, 9, 4, 8, 7 };
print(data);
mergeSort(data);
System.out.println("排序后的数组:");
print(data);
}
private static void mergeSort(int[] data) {
// TODO Auto-generated method stub
sort(data, 0, data.length - 1);
}
private static void sort(int[] data, int left, int right) {
// TODO Auto-generated method stub
if(left>=right)return;
int center = (left + right) / 2;
sort(data, left, center);
sort(data, center+1, right);
merge(data, left, center, right);
print(data);
}
private static void merge(int[] data, int left, int center, int right) {
// TODO Auto-generated method stub
int [] tempArray = new int[data.length];
int index = left;
int rightFirst = center + 1;
int temp = left;
while(left<=center && rightFirst<=right){
if(data[left]<data[rightFirst]){
tempArray[index++] = data[left++];
}else{
tempArray[index++] = data[rightFirst++];
}
}
while(left<=center){
tempArray[index++] = data[left++];
}
while(rightFirst<=right){
tempArray[index++] = data[rightFirst++];
}
while(temp<= right){
data[temp] = tempArray[temp++];
}
}
private static void print(int[] data) {
// TODO Auto-generated method stub
for (int i = 0; i < data.length; i++) {
System.out.print(data[i] + "\t");
}
System.out.println();
}
}
package sort;
/*
快�?排序是一个�?度非常快的交换排序算法,它的基本思路很简单,从待排的数据序列中任取一个数据(如第�?��数据)作为分界�?,所有比它小的数据元素放到左边,�?��比它大的数据元素放到它的右边。经过这样一趟下来,该序列形成左右两个子序列,左边序列中的数据元素的值都比分界�?小,右边序列中数据元素的值都比分界�?大�?
接下来对左右两个子序列进行�?归排序,对两个子序列重新选择中心元素并依此规则调整,直到每个元素子表的元素只剩下�?��元素,排序完成�?
思路�?
1.定义�?��i变量,i变量从左边第�?��索引�?��,找大于分界值的元素的索引,并用i来记录它�?
2.定义�?��j变量,j变量从右边第�?��索引�?��,找小于分界值的元素的索引,并用j来记录它�?
3.如果i<j,交换i,j两个索引处的元素�?
重复执行以上1,2,3步,直到i>=j,可以判断j左边的数据元素都小于分界值,j右边的数据元素都大于分界值,�?��将分界�?和j索引处的元素交换即可�?
时间复杂�?
�?��情况(每次�?是�?到中间�?作枢轴)T(n)=O(nlogn)
�?��情况(每次�?是�?到最小或�?��元素作枢轴)
做n-1趟,每趟比较n-i次,总的比较次数�?��:[O(n²)]
平均时间复杂度为::T(n)=O(nlogn)
*/
public class QuickSort {
/**
* @author ps
* 2012-7-19 上午03:01:38
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] data = new int[] { 5, 3, 6, 2, 1, 9, 4, 8, 7 };
// int[] data = new int[] { 25, 85, 56, 92, 11, 49, 38, 7 };
print(data);
// quickSort(data, 0, data.length - 1);
quickSort1(data, 0, data.length - 1);
System.out.println("排序后的数组:");
print(data);
}
public static void quickSort1(int[] data, int start, int end){
if (start >= end)
return;
int pivot = data[start];
int i = start;
int j = end;
while(i<j){
while(j>i && data[j]>pivot){
j--;
}
if(j>i){
swap(data,i,j);
}else{
break;
}
while(i<j && data[i]<pivot){
i++;
}
if(i<j){
swap(data,i,j);
}else{
break;
}
}
print(data);
quickSort1(data, start, j-1);
quickSort1(data, j+1, end);
}
private static void quickSort(int[] data, int start, int end) {
// TODO Auto-generated method stub
if (start >= end)
return;
//以起始索引为分界�?
int pivot = data[start];
int i = start + 1;
int j = end;
while (true) {
while (i <= end && data[i] < pivot) {
i++;
}
while (j > start && data[j] > pivot) {
j--;
}
if (i < j) {
swap(data, i, j);
} else {
break;
}
}
//交换 j和分界点的�?
swap(data, start, j);
print(data);
//递归左子序列
quickSort(data, start, j - 1);
//递归右子序列
quickSort(data, j + 1, end);
}
public static 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];
}
private static void print(int[] data) {
// TODO Auto-generated method stub
for (int i = 0; i < data.length; i++) {
System.out.print(data[i] + "\t");
}
System.out.println();
}
}
package sort;
/**
* @author ps
* 2012-7-18 上午03:09:59
* 直接选择排序
* 算法不稳定,O(1)的额外的空间,比较的时间复杂度为O(n^2),交换的时间复杂度为O(n),并不是自适应的。
* 在大多数情况下都不推荐使用。只有在希望减少交换次数的情况下可以用。
*/
public class SelectSort {
/**
* @author ps
* 2012-7-18 上午03:09:59
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] data = new int[] { 5, 3, 6, 2, 1, 9, 4, 8, 7 };
print(data);
//selectSort(data);
anotherSelectSort(data);
print(data);
}
/**
*
* @author ps
* 2012-7-18 上午06:21:34
* @param data
*/
private static void selectSort(int[] data) {
// TODO Auto-generated method stub
for(int i=0;i<data.length;i++){
for(int j=i+1;j<data.length;j++){
int temp = data[i];
if(data[i]>data[j]){
data[i] = data[j];
data[j] = temp;
}
}
print(data);
}
}
/**
*
* @author ps
* 2012-7-18 上午06:47:31
* @param data
*/
public static void anotherSelectSort(int[] data){
for(int i=0;i<data.length;i++){
int minIndex = i;
for(int j=i+1;j<data.length;j++){
if(data[j]<data[minIndex]){
minIndex = j;
}
}
if(minIndex != i){
swap(data,i,minIndex);
}
print(data);
}
}
/**
*
* @author ps
* 2012-7-18 上午06:51:44
* @param data
* @param i
* @param minIndex
*/
private static void swap(int[] data, int i, int j) {
data[i] = data[i] + data[j];
data[j] = data[i] - data[j];
data[i] = data[i] - data[j];
}
/**
* @author ps
* 2012-7-18 上午03:26:39
* @param data
*/
private static void print(int[] data) {
// TODO Auto-generated method stub
for(int i=0;i<data.length;i++){
System.out.print(data[i]+"\t");
}
System.out.println();
}
}