八大算法手写

一、八大排序简介

  1. 插入排序(直接插入排序,二分插入排序,shell排序)
  2. 交换排序(冒泡排序,快速排序)
  3. 选择排序(直接选择排序,堆排序)
  4. 归并排序
  5. 分配排序(基数排序)

1.  插入排序

思想:将每一个待排序序列,每一步都按顺序码插入到前面已经排序的子序列中,直到全部插入排序完为止。

/**
* 直接插入排序
* 思想:两次for循环,时间复杂度:O(n^2),空间复杂度:O(1)
* @param a
* @return
*/
public static int[] insertionSortDirect(int []a){
    for(int j=1;j<a.length;j++){
        int t=a[j];//待插入元素
        int i;
        for(i=j-1;i>=0&&a[i]>t;i--){
                a[i+1]=a[i];//将大于插入元素的往后移动一位
        }
        a[i+1]=t;
    }
    return a;
}
/**
* 二分插入排序
* 思想:按照折半查找,减少查找次数;时间复杂度:O(nlog2n);空间复杂度:O(1)
*/
public static int[] insertionSortTwo(int []a){
    for(int i=1;i<a.length;i++){
       int t=a[i],right=i-1,left=0;mid;
    while(right>=left){
      mid
=(right+left)/2;
      if(a[mid]<t){
        left
=mid+1;
      }
else{
        right
=mid-1;
      }
    }
     for(int j=i-1;j>=left;j--){
       a[j
+1]=a[j];//移动元素
     }
     if(left!=i){
       a[left]
=t;
     }
    }
  return a;
}

2.Shell排序

/**
* Shell排序
* 相当于分组排序,将间隔dk的元素放在同一组里,进行排序,时间复杂度:O(nlog2n);空间复杂度:O(1)
*/
public static int[] insertSortShell(int a[],int i){
    int dk=a.length/i;
    while(dk>=1){
        insertShell(a, dk);
        dk=dk/2;
    }
    return a;
}
public static void insertShell(int a[],int dk){
    for(int j=1;j<a.length;j++){
        int t=a[j];//待插入元素
        int i;
        for(i=j-dk;i>=0&&a[i]>t;i=i-dk){
                a[i+dk]=a[i];//将大于插入元素的往后移动一位
        }
        a[i+dk]=t;
    }
}

3.简单选择排序

/**
 * 简单选择排序
 * 思想:通过一次循环,找到最小值的下标,把最小值放在最前面,再在后面的数中继续寻找,直到倒数第二个
 */
private static void simpleSelectSort(int []a){
    int min;
    for(int i=0;i<a.length-1;i++){
        min=i;
        for(int j=i+1;j<a.length;j++){//找到最小值得下标
            if(a[j]<a[min]){
                min=j;
            }
        }
        swap(a,i,min);
    }
}
private static void swap(int a[],int i,int min){
    if(i==min){
        return;
    }
    a[i]+=a[min];
    a[min]=a[i]-a[min];
    a[i]=a[i]-a[min];
}
/**
* 二元选择排序
* 思想:与简单选择排序不同的是分别找出最大和最小
*/
private static void binarySelectSort(int []a){
    int max,min;
    for(int i=0;i<a.length/2;i++){
        min=max=i;
        for(int j=i+1;j<a.length-i;j++){
           if(a[j]<a[min]) {
        min=j;
          continue; } if(a[j]>a[max]) max=j; } swap(a, i, min); swap(a, a.length-i-1, max);
}

4. 改进的冒泡排序

/**
* 改进的冒泡排序
*/
private static void buddle(int []a){
    int high=a.length-1,low=0;
    while(low<high){
        for(int i=low;i<high;i++){
            if(a[i]>a[i+1]){
                swap(a,i,i+1);
            }
        }
        for(int i=high;i>low;i--){
            if(a[i]<a[i-1]){
                swap(a,i,i-1);
            }
        }
        ++low;
                --high;
    }
}
private static void swap(int[] a, int i, int j) {
    if(i==j) return;
    a[i]+=a[j];
    a[j]=a[i]-a[j];
    a[i]=a[i]-a[j];
}

5.堆排序

/**
堆排序
*思想:是一种树形结构,是对直接选择排序的有效改进。
*堆的定义如下:
*具有n个元素的序列(k1,k2,…,kn),当且仅当满足下面条件时称之为堆。
*Ki>=K2i,Ki>=K2i+1//Ki<=K2i,Ki<=K2i+1;
*初始时把要排序的数的序列看作是一棵顺序存储的二叉树,调整它们的存储序,使之成为一个堆,
*这时堆的根节点的数最大。然后将根节点与堆的最后一个节点交换。然后对前面(n-1)个数重新调整使之成为堆。
*依此类推,直到只有两个节点的堆,并对它们作交换,最后得到有n个节点的有序序列。从算法描述来看,堆排序需要两个过程,
*一是建立堆,二是堆顶与堆的最后一个元素交换位置。所以堆排序有两个函数组成。一是建堆的渗透函数,二是反复调用渗透函数实现排序的函数。
*/
public static void heapSort(int a[]){
    for(int i=0;i<a.length;i++){
        createMaxHeap(a,a.length-i);//创造最大的堆
        swap(a, 0, a.length - 1 - i);
        }
}
private static void swap(int[] a, int i, int j) {
    if(i==j) return;
    a[i]+=a[j];
    a[j]=a[i]-a[j];
    a[i]=a[i]-a[j];
}
private static void createMaxHeap(int[] a, int lastIndex) {
    //从最后一个节点lastIndex的父节点开始
    for(int i=(lastIndex-1)/2;i>=0;i--){
        int k=i;// 保存当前正在判断的节点
        while(2*k+1<lastIndex){// bigIndex总是记录较大节点的值,先赋值为当前节点的左子节点的索引
            int bigIndex = 2*k+1;
            if(bigIndex+1<lastIndex){
                if (a[bigIndex] < a[bigIndex + 1]) {// 若右子节点值比左子节点值大,则biggerIndex记录的是右子节点的索引
                            bigIndex++;
                        }
            }
            // 如果k节点的值小于其较大的子节点的值
            if (a[k] < a[bigIndex]) {
                // 交换两者的值
                swap(a, k, bigIndex);
                // 将biggerIndex赋予k,开始while循环的下一次循环,重新保证k节点的值大于其左右子节点的值
                k = bigIndex;
            } else {
                break;
            }
        }
    }
}

 6.归并排序

/**
 * 归并排序
 *思想:归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列.
*/
private static void sort(int []q,int left,int right) {
    if(left<right){
        int center=(left+right)/2;
        sort(q,left,center);
        sort(q,center+1,right);
        marge(q,left,center,right);
    }
}
private static void marge(int[] q, int left, int center, int right) {
    int third[]=new int[q.length];
    int mid=center+1;
    int tleft=left;
    int tem=left;
    while(left<=center&&mid<=right){
        if(q[left]<=q[mid]){
            third[tleft++]=q[left++];
        }else{
            third[tleft++]=q[mid++];
        }
    }
    while(mid<=right){
        third[tleft++]=q[mid++];
    }
    while(left<=center){
        third[tleft++]=q[left++];
    }
    while(tem<=right){
        q[tem]=third[tem++];
    }
}

7. 快速排序

/**
 * 快速排序
 * 思想:基本思想:选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,
 * 此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。
*/
    private static void quickSort(int []a,int low,int high){
        if(low<high){
            int mid=getMiddle(a, low, high);
            quickSort(a, low, mid-1);
            quickSort(a, mid+1, high);
        }
    }
    private static int getMiddle(int []a,int low,int high){
        int tem=a[low];
        while(low<high){
            while(low<high&&a[low]<=tem){
                low++;
            }
            a[low]=a[high];
            while(low<high&&a[high]>=tem){
                high--;
            }
            a[high]=a[low];
        }
        a[low]=tem;
        return low;
    }    

8.基数排序

/**
 * 基数排序
 * 思想:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。
这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列
*/ private static int[] radixSort(int[] a) { int max=a[0]; //首先确定排序趟数 for(int i=0;i<a.length-1;i++){ if(a[i]>max) max=a[i]; } int t=0; while(max>0){ max/=10; t++;//位数} //建立十个队列 ArrayList<ArrayList<Integer>> arr=new ArrayList<>(); for(int i=0;i<10;i++){ ArrayList<Integer> queue=new ArrayList<>(); arr.add(queue); } //进行t次收集和处理 for(int i=0;i<t;i++){ //分配数组元素 for(int as:a){ //得到数据的第t+1位的数 int x= as%(int)Math.pow(10, i+1)/(int)Math.pow(10, i); ArrayList<Integer> que=arr.get(x); que.add(as); arr.set(x, que); } int count=0;//元素计数器 for(int k=0;k<10;k++){ while(arr.get(k).size()>0){ ArrayList<Integer> q=arr.get(k); a[count]=q.get(0); q.remove(0); count++; }
        }
      }
return a; }

猜你喜欢

转载自www.cnblogs.com/chen2608/p/12683089.html