几个经典排序算法自己手写一下练习练习
1、冒泡排序
private static int[] bubleSort(int[] arr) {
for(int i=0;i<arr.length;i++){
for(int j=0;j<arr.length-i-1;j++){
if(arr[j]>arr[j+1]){
int tmp=arr[j+1];
arr[j+1]=arr[j];
arr[j]=tmp;
}
}
}
return arr;
}
最简单的冒泡排序,没什么多说的,两个for循环,每次循环把最大的数排到后面。
冒泡排序最好的时间复杂度为O(n),最差的时间复杂度为O(n²),平均时间复杂度为O(n²);
2、插入排序
给定一个数组{8,7,9,5,6,4,0,1,2,3},for循环,从7遍历到3,从第2个元素7开始,与前面各个元素比较,将它插入到前面数组中相应的位置。比如5插入到{1,2,3,4,6,10}中的4和6之间。
private static int[] insertSort(int[] arr) { //插入排序
for(int i=1;i<arr.length;i++){
int tmp=arr[i];
for(int j=i-1;j>=0;j--){
if(tmp<arr[j]){
arr[j+1]=arr[j];
arr[j]=tmp;
}
if(tmp>arr[j]){
break;
}
}
}
return arr;
}
空间复杂度O(1)
时间复杂度O(n2)
最差情况:反序,需要移动n*(n-1)/2个元素
最好情况:正序,不需要移动元素
数组在已排序或者是“近似排序”时,插入排序效率的最好情况运行时间为O(n);
插入排序最坏情况运行时间和平均情况运行时间都为O(n²)。
3、希尔排序
基于插入排序的思想,增加了步长,一般先取array.length/2,然后依次二分直到为1。每次对第i个,i+step,i+2step等等元素进行插入排序。
例:{6,3,4,5,1,7,2,9,10,8}
第一次排序,step为10/2=5,第一次分为5组,每组为{6,7}{3,2}{4,9}{5,10}{1,8}
排序之后为{6,2,4,5,1,7,3,9,10,8}
第二次排序,step为5/2=2,分2组,每组为{6,4,1,2,10}{3,5,7,9,8}
排序之后为{1,3,2,5,4,7,6,8,10,9}
最后一次排序,step为1,插入排序。
private static int[] shellSort(int[] array) {
int step=array.length/2;
while(step>0){
System.out.println("step="+step);
for(int i=0;i<step;i++){
for(int j=i+step;j<array.length;j=j+step){
int k=j;
int tmp=array[k];
while(k>=0){
if(tmp<array[k]){
array[k+step]=array[k];
array[k]=tmp;
}
if(tmp>array[k]){
break;
}
k=k-step;
}
}
}
step=step/2;
}
return array;
}
平均时间复杂度O(n的1.3次方)(这个牛逼了,居然还有1.3次方)
最好情况O(n),最坏情况O(n²)。
4、简单选择排序
从i=0开始循环,每次选出最小或者最大的元素与第 i个元素交换,跟冒泡排序有点像。
private static int[] selectSort(int[] array) { //选择排序
for(int i=0;i<array.length;i++){
int min=Integer.MAX_VALUE;
int minJ=0;
for(int j=i;j<array.length;j++){
if(array[j]<min){
min=array[j];
minJ=j;
}
}
array[minJ]=array[i];
array[i]=min;
}
return array;
}
时间复杂度为O(n²)。
5、归并排序
分治法的经典例子,先把数组二分二分再二分,直到分为只剩一个元素,然后再两两比较大小,归并。
public class mergeSort {
public static void main(String[] args) {
int[] array={6,3,4,5,1,7,2,9,10,8};
mergeSort(array,0,array.length-1);
for(int i=0;i<array.length;i++){
System.out.print(array[i]+" ");
}
}
private static void mergeSort(int[] array,int left,int right) { //归并排序
if (left >= right) return;
int mid=(left+right)/2;
System.out.println("mid = "+mid);
mergeSort(array,left,mid); //对左半边二分
mergeSort(array,mid+1,right); //对右半边二分
merge(array,left,mid,mid+1,right); //左右合并
}
private static int[] merge(int[] array,int leftS,int leftE,int rightS,int rightE) { //归并排序
System.out.println("sort "+"leftS="+leftS+" leftE="+leftE+" to "+"rightS="+rightS+ "rightE="+rightE);
int[] temp = new int[rightE-leftS+ 1];
int i=leftS;
int j=rightS;
int k=0;
while(i<=leftE&&j<=rightE){
if(array[i]<array[j]){
temp[k++] = array[i++];
}
else{
temp[k++] = array[j++];
}
}
while (i <= leftE) {
temp[k++] = array[i++];
}
while (j <= rightE) {
temp[k++] = array[j++];
}
k = leftS;
// 将临时数组中的内容拷贝回原数组中 // (原left-right范围的内容被复制回原数组)
for (int element : temp) {
array[k++] = element;
System.out.println("element = "+element);
}
for(int z=0;z<array.length;z++){
System.out.print(array[z]+" ");
}
System.out.println(000);
return array;
}
}
时间复杂度无论是在最好情况下还是在最坏情况下均是O(nlgn),开辟了一个temp空间去暂存数组,所以空间复杂度为O(n)。
6、快速排序
每次选择数组的第一个数为基准数,与后面的数比较,大的放基准数后面,小的放前面。具体实现是设定一个low和high,从高位开始与基准比较,小的话将array[high]与基准数交换,然后从array[low]开始比较,大于基准数的话就和array[high]交换。这样运行到low=high时,基准数被交换到了array[low],对左右数组array[l],array[low-1],继续递归进行排序。
public class quickSort {
public static void main(String[] args) {
int[] array={6,3,4,5,1,7,2,9,10,8};
quickSort(array,0,array.length-1);
for(int i=0;i<array.length;i++){
System.out.print(array[i]+" ");
}
}
private static void quickSort(int[] array, int l, int h) {
int low =l;
int high=h;
int target=array[low];
while(low<high){
while(low<high&&array[high]>target){
high--;
}
if(array[high]<target){
int temp = array[low];
array[low]=array[high];
array[high]=temp;
low++;
}
while(low<high&&array[low]<target){
low++;
}
if(array[low]>target){
int temp = array[low];
array[low]=array[high];
array[high]=temp;
high--;
}
}
//当low==high时,本次排序结束,对low前后各半边再排序
if(low>l) quickSort(array,l,low-1);
if(high<h) quickSort(array,high+1,h);
}
}
平均时间复杂度为O(nlogn),最差为O(n²)
7、堆排序
堆顶元素为最大,左右孩子节点都小于父节点。每次调整时比较孩子节点和父节点,将最大值放在父节点。
(1)构建大根堆
(2)堆顶元素放到最后
(3)对剩下元素重新构建大根堆
(4)重复(2)(3)步直到全部输出
public class HeapSort {
public static void main(String[] args) {
int[] array = {6,3,4,5,1,7,2,9,10,8};
System.out.println("Before heap:");
printArray(array);
heapSort(array);
System.out.println("After heap sort:");
printArray(array);
}
public static void printArray(int[] array) {
System.out.print("{");
for (int i = 0; i < array.length; i++) {
System.out.print(array[i]);
if (i < array.length - 1) {
System.out.print(", ");
}
}
System.out.println("}");
}
public static void exchangeElements(int[] array, int index1, int index2) {
int temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
}
public static void heapSort(int[] array) {
if (array == null || array.length <= 1) {
return;
}
buildMaxHeap(array);
for (int i = array.length - 1; i >= 1; i--) {
exchangeElements(array, 0, i);
maxHeap(array, i, 0);
}
}
private static void buildMaxHeap(int[] array) {
if (array == null || array.length <= 1) {
return;
}
int half = array.length / 2;
for (int i = half; i >= 0; i--) {
maxHeap(array, array.length, i);
}
}
private static void maxHeap(int[] array, int heapSize, int index) {
int left = index * 2 + 1;
int right = index * 2 + 2;
int largest = index;
if (left < heapSize && array[left] > array[index]) {
largest = left;
}
if (right < heapSize && array[right] > array[largest]) {
largest = right;
}
if (index != largest) {
exchangeElements(array, index, largest);
maxHeap(array, heapSize, largest);
}
}
}