冒泡排序
冒泡排序是所有排序算法中最简单、最基本的一种。冒泡排序法的思路就是交换排序,通过相邻元素比较交换来达到排序的目的,其算法实现与“冒泡”过程相似。
时间复杂度:O(n^2)
空间复杂度:O(k)
//package com.wu.demo;
public class BubbleSort {
public static void main(String[] args) {
int[] numbers = {1,3,6,4,8,2,7,10,9,5,5};
System.out.println("冒泡排序前:");
for(int e : numbers) {
System.out.print(e+" ");
}
System.out.println();
for(int i = 1;i<numbers.length;i++) { // 最多遍历数组长度减一就可以了
for(int j = 0;j<=numbers.length-i-1;j++) { // 最大值往数组后推(冒泡) 当然有效范围也要减一
if(numbers[j]>numbers[j+1]) {
// 交换两个数值
numbers[j] = numbers[j]^numbers[j+1];
numbers[j+1] = numbers[j]^numbers[j+1];
numbers[j] = numbers[j]^numbers[j+1];
}
}
}
System.out.println("冒泡排序后:");
for(int e : numbers) {
System.out.print(e+" ");
}
}
}
结果显示:
选择排序
也是比较简单的排序算法,思路比较直观,选择排序算法在每一步选取最小值来重新排序,从而达到排序的目的。
时间复杂度:O(n^2)
空间复杂度:O(k)
//package com.wu.demo;
public class SelectionSort {
public static void main(String[] args) {
int[] numbers = {1,3,6,4,8,2,7,10,9,5,5};
System.out.println("选择排序前:");
for(int e : numbers) {
System.out.print(e+" ");
}
System.out.println();
for(int i = 0;i < numbers.length-1;i++) {
int temp = i; // 记录最小值的下标
for(int j = i+1;j<numbers.length;j++) {
if(numbers[j]<numbers[temp]) {
temp = j;
}
}
if(temp != i) {
numbers[temp] = numbers[temp]^numbers[i];
numbers[i] = numbers[temp]^numbers[i];
numbers[temp] = numbers[temp]^numbers[i];
}
}
System.out.println("选择排序后:");
for(int e : numbers) {
System.out.print(e+" ");
}
}
}
结果显示:
插入排序
通过对未排序的数据逐个插入合适的位置而完成的排序工作,插入排序算法的思路也比较简单,使用较为广泛。
时间复杂度:O(n^2)
空间复杂度:O(k)
//package com.wu.demo;
public class InsertSort {
public static void main(String[] args) {
int[] numbers = {1,3,6,4,8,2,7,10,9,5,5};
System.out.println("插入排序前:");
for(int e : numbers) {
System.out.print(e+" ");
}
System.out.println();
for(int i = 1;i<numbers.length;i++) {
int temp = numbers[i];
int j = i - 1;
for(;j>=0;j--) {
if(numbers[j] > temp) {
numbers[j+1] = numbers[j];
}
else {
break; // 此处有坑
}
}
numbers[j+1] = temp;
}
System.out.println("插入排序后:");
for(int e : numbers) {
System.out.print(e+" ");
}
}
}
结果显示:
希尔排序
整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
时间复杂度:O(n^(3/2))
空间复杂度:O(k)
//package com.wu.demo;
public class ShellSort{
public static void main(String[] args) {
int[] numbers = {1,3,6,4,8,2,7,10,9,5,5};
System.out.println("希尔排序前:");
for(int e : numbers) {
System.out.print(e+" ");
}
System.out.println();
int gap = numbers.length;
while(gap>1) {
gap /= 2;
// 对于每一组遍历
for(int i = 0;i<gap;i++) {
// 对该组数字未排序部分遍历
for(int j = i+ gap;j<numbers.length;j += gap) { // 此处有坑
// 记录未排序部分的第一个数字
int temp = numbers[j];
// 以下为已排序部分的遍历
int k = j-gap;
for(; k >= 0;k-=gap) {
if(temp < numbers[k]) {
numbers[k+gap] = numbers[k];
}else{
break; // 此处有坑
}
}
numbers[k+gap] = temp;
}
}
}
System.out.println("希尔排序后:");
for(int e:numbers) {
System.out.print(e+" ");
}
}
}
结果显示:
快速排序
和冒泡算法类似,都是基于交换排序的思想,但是快速排序对冒泡排序进行了改进,从而具有更高的执行效率。
时间复杂度:O(nlogn)
空间复杂度:O(k)
//package com.wu.demo;
public class QuickSort {
public static void quickSort(int[] numbers,int left,int right) {
if(right <= left) {
return;
}
// 返回分界值下标
int border = partSort(numbers,left,right);
// 递归调用左边部分
quickSort(numbers,left,border-1);
// 递归调用右边部分
quickSort(numbers,border+1,right);
}
public static int partSort(int[] numbers,int left,int right) {
// 确定基准值
int base = numbers[left];
while(left < right) {
// 右边找到其小于等于base的相应下标 这里先从队尾开始
while(numbers[right] >= base && right>left) {
right--;
}
// 将right位置的值赋值给left位置
numbers[left] = numbers[right];
// 左边找到其大于等于base的相应下标
while(numbers[left] <= base && left<right) {
left++;
}
// 将left位置的值赋值给right位置
numbers[right] = numbers[left];
}
// 最后还要将base赋值给left位置
numbers[left] = base;
return left;
}
public static void main(String[] args) {
int[] numbers = {1,3,6,4,8,2,7,10,9,5,5};
System.out.println("快速排序前:");
for(int e : numbers) {
System.out.print(e+" ");
}
System.out.println();
QuickSort.quickSort(numbers,0,numbers.length-1);
System.out.println("快速排序后:");
for(int e:numbers) {
System.out.print(e+" ");
}
}
}
结果显示:
归并排序
归并排序 (merge sort) 是一类与插入排序、交换排序、选择排序不同的另一种排序方法。归并的含义是将两个或两个以上的有序表合并成一个新的有序表。归并排序有多路归并排序、两路归并排序 , 可用于内排序,也可以用于外排序。这里仅对内排序的两路归并方法进行讨论。
时间复杂度:O(nlogn)
空间复杂度:O(n)
//package com.wu.demo;
public class MergerSort{
public static void mergerSort(int[] numbers , int left , int right){
if(left < right){
int mid = (left + right)/2;
mergerSort(numbers,left,mid);
mergerSort(numbers,mid+1,right);
Merger(numbers,left,mid,right);
}
}
public static void Merger(int[] numbers ,int left ,int mid , int right){
int[] temp = new int[right - left + 1]; // 辅助数组
int i = left;
int j = mid + 1;
int k = 0;
while(i<=mid && j<=right){
if(numbers[i] < numbers[j]){
temp[k++] = numbers[i++];
}else{
temp[k++] = numbers[j++];
}
}
while(i<=mid){
temp[k++] = numbers[i++];
}
while(j<=right){
temp[k++] = numbers[j++];
}
System.arraycopy(temp,0,numbers,left,right- left + 1);
}
public static void main(String[] args){
int[] numbers = {1,3,6,4,8,2,7,10,9,5,5};
System.out.println("归并排序前:");
for(int e : numbers) {
System.out.print(e+" ");
}
System.out.println();
MergerSort.mergerSort(numbers,0,numbers.length-1);
System.out.println("归并排序后:");
for(int e:numbers) {
System.out.print(e+" ");
}
}
)
结果显示:
所有算法消耗时间测试:
package com.wu;
import java.util.Random;
public class MyArrayList{
/**
* 冒泡排序
* @param numbers 待排序的数组
* @return 已经排序好的数组
*/
public static void bubbleSort(int[] numbers) {
for(int i = 1;i<numbers.length;i++) { // 最多遍历数组长度减一就可以了
for(int j = 0;j<=numbers.length-i-1;j++) { // 最大值往数组后推(冒泡) 当然有效范围也要减一
if(numbers[j]>numbers[j+1]) {
// 交换两个数值
numbers[j] = numbers[j]^numbers[j+1];
numbers[j+1] = numbers[j]^numbers[j+1];
numbers[j] = numbers[j]^numbers[j+1];
}
}
}
}
/**
* 选择排序
* @param numbers 待排序数组
* @return 已经排序好的数组
*/
public static void seclectionSort(int[] numbers) {
for(int i = 0;i < numbers.length-1;i++) {
int temp = i; // 记录最小值的下标
for(int j = i+1;j<numbers.length;j++) {
if(numbers[j]<numbers[temp]) {
temp = j;
}
}
if(temp != i) {
numbers[temp] = numbers[temp]^numbers[i];
numbers[i] = numbers[temp]^numbers[i];
numbers[temp] = numbers[temp]^numbers[i];
}
}
}
/**
* 插入排序
* @param numbers 待排序的数组
* @return 已经排序好的数组
*/
public static void insertSort(int[] numbers) {
for(int i = 1;i<numbers.length;i++) {
int temp = numbers[i];
int j = i - 1;
for(;j>=0;j--) {
if(numbers[j] > temp) {
numbers[j+1] = numbers[j];
}
else {
break; // 此处有坑
}
}
numbers[j+1] = temp;
}
}
/**
* 希尔排序
* @param numbers 待排序的数组
* @return 已经排序好的数组
*/
public static void shellSort(int[] numbers) {
int gap = numbers.length;
while(gap>1) {
gap /= 2;
// 对于每一组遍历
for(int i = 0;i<gap;i++) {
// 对该组数字未排序部分遍历
for(int j = i+ gap;j<numbers.length;j += gap) { // 此处有坑
// 记录未排序部分的第一个数字
int temp = numbers[j];
// 以下为已排序部分的遍历
int k = j-gap;
for(; k >= 0;k-=gap) {
if(temp < numbers[k]) {
numbers[k+gap] = numbers[k];
}else{
break; // 此处有坑
}
}
numbers[k+gap] = temp;
}
}
}
}
/**
* 快速排序
* @param numbers 待排序的数组
* @param left 数组的起始位置
* @param right 数组的结尾位置
*/
public static void quickSort(int[] numbers,int left,int right) {
if(right <= left) {
return;
}
// 返回分界值下标
int border = partSort(numbers,left,right);
// 递归调用左边部分
quickSort(numbers,left,border-1);
// 递归调用右边部分
quickSort(numbers,border+1,right);
}
public static int partSort(int[] numbers,int left,int right) {
// 确定基准值
int base = numbers[left];
while(left < right) {
// 右边找到其小于等于base的相应下标 这里先从队尾开始
while(numbers[right] >= base && right>left) {
right--;
}
// 将right位置的值赋值给left位置
numbers[left] = numbers[right];
// 左边找到其大于等于base的相应下标
while(numbers[left] <= base && left<right) {
left++;
}
// 将left位置的值赋值给right位置
numbers[right] = numbers[left];
}
// 最后还要将base赋值给left位置
numbers[left] = base;
return left;
}
/**
* 归并排序
* @param numbers
* @param left
* @param right
*/
public static void MergerSort(int[] numbers , int left , int right){
if(left < right){
int mid = (left + right)/2;
MergerSort(numbers,left,mid);
MergerSort(numbers,mid+1,right);
Merger(numbers,left,mid,right);
}
}
public static void Merger(int[] numbers ,int left ,int mid , int right){
int[] temp = new int[right - left + 1]; // 辅助数组
int i = left;
int j = mid + 1;
int k = 0;
while(i<=mid && j<=right){
if(numbers[i] < numbers[j]){
temp[k++] = numbers[i++];
}else{
temp[k++] = numbers[j++];
}
}
while(i<=mid){
temp[k++] = numbers[i++];
}
while(j<=right){
temp[k++] = numbers[j++];
}
System.arraycopy(temp,0,numbers,left,right- left + 1);
}
public static void main(String[] args) {
int[] numbers = new int[100000];
Random random = new Random(0);
for(int i = 0 ; i<100000;i++) {
numbers[i] = random.nextInt(1000)+1;
}
int[] temp = new int[100000];
System.arraycopy(numbers, 0, temp, 0, temp.length);
long start1 = System.currentTimeMillis();
MyArrayList.bubbleSort(temp);
long end1 = System.currentTimeMillis();
System.out.println("冒泡排序时间花销:"+(end1-start1)+"ms");
System.arraycopy(numbers, 0, temp, 0, temp.length);
long start2 = System.currentTimeMillis();
MyArrayList.seclectionSort(temp);
long end2 = System.currentTimeMillis();
System.out.println("选择排序时间花销:"+(end2-start2)+"ms");
System.arraycopy(numbers, 0, temp, 0, temp.length);
long start3 = System.currentTimeMillis();
MyArrayList.insertSort(temp);
long end3 = System.currentTimeMillis();
System.out.println("插入排序时间花销:"+(end3-start3)+"ms");
System.arraycopy(numbers, 0, temp, 0, temp.length);
long start4 = System.currentTimeMillis();
MyArrayList.shellSort(temp);
long end4 = System.currentTimeMillis();
System.out.println("希尔排序时间花销:"+(end4-start4)+"ms");
System.arraycopy(numbers, 0, temp, 0, temp.length);
long start5 = System.currentTimeMillis();
MyArrayList.quickSort(temp,0,temp.length-1);
long end5 = System.currentTimeMillis();
System.out.println("快速排序时间花销:"+(end5-start5)+"ms");
System.arraycopy(numbers,0,temp,0,temp.length);
long start6 = System.currentTimeMillis();
MyArrayList.MergerSort(temp,0,temp.length-1);
long end6 = System.currentTimeMillis();
System.out.println("归并排序时间花销:"+(end6-start6)+"ms");
}
}
运行结果: