您的位置:首页 > 编程语言 > Java开发

Java排序算法以及算法改进总结(冒泡、选择、插入、归并、快速排序)

2017-10-09 19:49 597 查看
算法复习,代码是最好的说明!

一、冒泡排序:

算法:

比较相邻的元素。如果第一个比第二个大,就交换他们两个。

对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。

针对所有的元素重复以上的步骤,除了最后一个。

持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

分析:

平均最好最坏辅助存储稳定性
O(n^2)O(n)O(n^2)O(1)稳定

代码:

/**
* 冒泡排序
* @param array
*/
void bubbleSort_1(int[] array){
for (int i = array.length-1; i >0 ; i--) {
for (int j = 0; j <i ; j++) {
if (array[j]>array[j+1]){
swap(array,j,j+1);
}
}
}
}

/**
* 冒泡排序改进,标志某一趟排序过程中是否有数据交换,如果进行某一趟排序时并没有进行数据交换,则说明数据已经按要求排列好,可立即结束排序,避免不必要的比较过程
* @param array
*/
void bubbleSort_2(int[] array){
boolean isSwaped;
for (int i = array.length-1; i >0 ; i--) {
isSwaped = false;
for (int j = 0; j <i ; j++) {
if (array[j]>array[j+1]){
swap(array,j,j+1);
isSwaped = true;
}

}
if (!isSwaped)
break;
}

}

/**
* 冒泡排序改进,设置一个pos指针,pos后面的数据在上一轮排序中没有发生交换,下一轮排序时,就对pos之后的数据不再比较
* @param array
*/
void bubbleSort_3(int[] array){
int end = array.length - 1;
while (end>0) {
int pos = 1;
for (int j = 1; j <=end; j++) {
if (array[j-1] > array[j]) {
swap(array, j-1, j);
pos = j;
}
}
end = pos - 1;

}
}

/**
* 鸡尾酒排序,也叫定向冒泡排序,是冒泡排序的一种改进。此算法与冒泡排序的不同处在于从低到高然后从高到低,而冒泡排序则仅从低到高去比较序列里的每个元素。他可以得到比冒泡排序稍微好一点的效能。
* @param array
*/
void bubbleSort_4(int[] array){
int left = 0;
int right = array.length-1;
while (left < right){
for (int i = left; i <right ; i++) {
if (array[i] > array[i+1]) swap(array,i,i+1);
}
right--;

for (int i = right; i >left ; i--) {
if (array[i] < array[i-1]) swap(array,i,i-1);
}
left++;
}
}

void swap(int[] array,int i,int j){
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}


二、选择排序:

算法:

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。

分析:

平均最好最坏辅助存储稳定性
O(n^2)O(n^2)O(n^2)O(1)不稳定

代码:

/**
* 选择排序
* @param array
*/
void selectionSort_1(int[] array){

for (int i = 0; i <array.length-1 ; i++) {
int min = i;

for (int j = i+1; j < array.length; j++) {
if (array[j]<array[min]){
min = j;
}

}

if (min!=i) swap(array,min,i);

}
}

/**
* 选择排序改进,每趟排序确定两个最值——最大值与最小值,这样就可以将排序趟数缩减一半。
* @param array
*/
void selectionSort_2(int[] array){
int left = 0;
int right = array.length-1;

while (left<right){
int min = left;
int max = right;

for (int i = left; i <=right; i++) {
if (array[i]<array[min]) min = i;
if (array[i]>array[max]) max = i;
}

if (min!=left) swap(array,min,left);
if (max!=right&&max!=left) swap(array,max,right);

left++;
right--;

}

}


三、插入排序:

1、直接插入排序:

算法:

从第一个元素开始,该元素可以认为已经被排序

取出下一个元素,在已经排序的元素序列中从后向前扫描

如果该元素(已排序)大于新元素,将该元素移到下一位置

重复步骤3,直到找到已排序的元素小于或者等于新元素的位置

将新元素插入到该位置后

重复步骤2~5

分析:

平均最好最坏辅助存储稳定性
O(n^2)O(n)O(n^2)O(1)稳定

代码:

/**
* 插入排序,写法一
* @param array
*/
void insertionSort_1(int[] array){
for (int i = 1; i < array.length; i++) {
int get = array[i];
int j = i-1;
while (j>=0&&array[j]>get){
array[j+1] = array[j];
j--;
}
array[j+1] = get;

}
}

/**
* 插入排序,写法二
* @param array
*/
void insertionSort_2(int[] array){
for (int i = 1; i < array.length; i++) {
for (int j = i; j >0 ; j--) {
if (array[j]<array[j-1]) swap(array,j,j-1);
else break;
}

}
}


2、二分插入排序:

算法:

利用二分法的思想对插入排序进行改进。

分析:

平均最好最坏辅助存储稳定性
O(n^2)O(nlogn)O(n^2)O(1)不稳定

代码:

/**
* 插入排序改进二分法插入
* @param array
*/
void insertionSortDichotomy(int[] array){
for (int i = 1; i < array.length; i++) {
int get = array[i];
int left = 0;
int right = i - 1;
while (left<=right){
int mid = (left+right)/2;
if (array[mid]<get)
left = mid + 1;
else
right = mid - 1;

}

for (int j = i-1; j >=left; j--) {
array[j+1] = array[j];
}
array[left] = get;

}

}


3、希尔插入排序:

算法:

先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量 =1( < …<d2<d1),即所有记录放在同一组中进行直接插入排序为止。

分析:

平均最好最坏辅助存储稳定性
O(n^2)O(n^1.3)O(n^2)O(1)不稳定

代码:

/**
* 插入排序改进希尔排序,写法一
* @param array
*/
void shellSort_1(int[] array){

for (int gap = array.length/2; gap >0 ; gap/=2) {

for (int i = 0; i < gap; i++) {

for (int j = i+gap; j < array.length; j+=gap) {
int get = array[j];
int k = j-gap;

while (k>=0&&array[k]>get){
array[k+gap]=array[k];
k-=gap;
}
array[k+gap] = get;

}

}

}
}

/**
* 插入排序改进希尔排序,写法二
* @param array
*/
void shellSort_2(int[] array){

for (int gap = array.length/2; gap >0 ; gap/=2) {

for (int i = 0; i < gap; i++) {

for
bc8d
(int j = i+gap; j < array.length; j+=gap) {

for (int k = j; k >=gap ; k-=gap) {
if (array[k]<array[k-gap]) swap(array,k,k-gap);
else break;

}

}

}

}
}


四、归并排序:

算法:

归并排序的实现分为递归实现与非递归(迭代)实现。归并排序算法主要依赖归并(Merge)操作,归并操作指的是将两个已经排序的序列合并成一个序列的操作

申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

设定两个指针,最初位置分别为两个已经排序序列的起始位置

比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

重复步骤3直到某一指针到达序列尾

将另一序列剩下的所有元素直接复制到合并序列尾

分析:

平均最好最坏辅助存储稳定性
O(nlogn)O(nlogn)O(nlogn)O(n)稳定

代码:

/**
* 将两个已经排序的序列合并成一个序列的操作
* @param array
* @param left
* @param mid
* @param right
*/
void merge(int[] array,int left,int mid,int right){
int[] temp = new int[right-left+1];
int index = 0;
int i = left;
int j = mid+1;

while (i<=mid&&j<=right)
temp[index++] = array[i] <= array[j] ? array[i++] : array[j++];

while (i<=mid)
temp[index++] = array[i++];

while (j<=right)
temp[index++] = array[j++];

for (int k = 0; k <right-left+1; k++)
array[left+k] = temp[k];

}

/**
* 递归实现
* @param array
* @param left
* @param right
*/
void MergeSortRecursion(int[] array,int left,int right){
if (left==right) return;

int mid = (left+right)/2;
MergeSortRecursion(array,left,mid);
MergeSortRecursion(array,mid+1,right);

merge(array,left,mid,right);
}

/**
* 非递归实现
* @param array
*/
void MergeSortIteration(int[] array){
int left,mid,right;

for (int i = 1; i < array.length; i*=2) {
left = 0;
while (left+i < array.length){
mid = left + i - 1;
right = mid + i < array.length ? mid + i : array.length - 1;
merge(array,left,mid,right);
left = right + 1;

}

}
}


五、快速排序:

算法:

从序列中挑出一个元素,作为"基准"(pivot)。

把所有比基准值小的元素放在基准前面,所有比基准值大的元素放在基准的后面(相同的数可以到任一边),这个称为分区(partition)操作。

对每个分区递归地进行步骤1~2,递归的结束条件是序列的大小是0或1,这时整体已经被排好序了。

分析:

平均最好最坏辅助存储稳定性
O(nlogn)O(nlogn)O(n^2)O(nlogn)不稳定

代码:

/**
*
* @param array
* @param left
* @param right
* @return
*/
int partition_1(int[] array, int left, int right){
int pivot = array[right];
int tail = left-1;

for (int i = left; i < right; i++) {
if (array[i] < pivot) swap(array,++tail,i);

}

swap(array,++tail,right);
return tail;

}

/**
* 改进将pivot的选择随机化,不再是固定选择左端点,或采用三支取中
* @param array
* @param left
* @param right
* @return
*/
int partition_2(int[] array, int left, int right){
swap(array,right, left+new Random().nextInt(right-left+1));
int pivot = array[right];
int tail = left-1;

for (int i = left; i < right; i++) {
if (array[i] < pivot) swap(array,++tail,i);

}

swap(array,++tail,right);
return tail;

}

/**
* 改进使用两个索引i和j,分别从左右两端进行扫描,i扫描到大于等于pivot的元素就停止,j扫描到小于等于pivot的元素也停止,交换两个元素,持续这个过程直到两个索引相遇,此时的pivot的位置就落在了j,然后交换pivot和j的位置
* @param array
* @param left
* @param right
* @return
*/
int partition_3(int[] array, int left, int right){
swap(array,right, left+new Random().nextInt(right-left+1));
int pivot = array[right];

int i = left - 1;
int j = right;

while (true){
do {
i++;
}while (i<=right&&array[i]<pivot);

do {
j--;
}while (j>=left&&array[j]>pivot);

if (j < i) break;

swap(array,i,j);
}

swap(array,++j,right);

return j;

}

/**
*
* @param array
* @param left
* @param right
*/
void quickSort(int[] array, int left, int right){
if (left>=right) return;

int pivot_index = partition_3(array,left,right);
quickSort(array,left,pivot_index-1);
quickSort(array,pivot_index+1,right);

}


参考链接:

 http://www.cnblogs.com/eniac12/p/5329396.html#s5

 http://blog.csdn.net/morewindows/article/details/6668714

 http://blog.csdn.net/hguisu/article/details/7776068
http://www.blogjava.net/killme2008/archive/2010/09/08/quicksort_optimized.html
如有错误,欢迎纠正!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐