Java算法结构

直接插入排序


        int a[] ={2,4,5,6,3,1,7,8,3};

        //排序算法:稳定的算法,不会改变相同数字在数组的前后顺序; 
        //复杂度为O(n^2);
        /*
        快速排序:直接插入排序(Insertion Sort)的基本思想是:
         每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子序列中的适当位置,
         直到全部记录插入完成为止:时间复杂度为:O(1+2+3+...+(n-1)) = O(n^2)
        */

        Insertsort(a);

        for(int element : a){
            System.out.print(element+" ");
        }

    private void Insertsort(int[] a) {

        int i , j ;

        for (i = 1; i < a.length; i++) {

            for ( j = i-1; j >= 0 && a[j] > a[j+1] ; j--) {

                int temp = a[j] ;
                a[j] = a[j+1]  ;
                a[j+1] = temp;

            }
        }

    }

数组中的相同数字的总个数

     /**
     * 有序数组中的相同数字的个数,时间复杂度为O(n);
     */
    private void equalAll() {

        int a[] = {2,2,2,3,4,5,5,6,6,6,7};
        int count = 0 ;

        //标示符,用于标示上次循环是否相同;
        boolean flag = false ;

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

            if (a[i] == a[i+1]){

                flag = true ;

                count ++ ;


            }else {

                if (flag){

                    flag = false ;

                    count++  ;

                }

            }

        }

        System.out.println("相同的元素总共有:" + count);
    }

去重排序

 /**
     * 去重,使用集合的方式,时间复杂度为O(n^2);
     */
    private void setAndList() {

        int[] nums = { 5, 6, 6, 6, 8, 8, 8 , 7 , 9 , 9 , 9 };
        List<Integer> numList = new ArrayList<Integer>();
        for (int i : nums){

            if (!numList.contains(i)){

                numList.add(i);
            }

        }
        System.out.println(numList);

    }
    /**
     * 使用数组的复制也可以
     * 时间复杂度为O(n^2)
     */
    private void setAndList2() {
        int arr[] ={2,4,5,6,3,1,7,8,3, 9 , 9 };
        //用来记录去除重复之后的数组长度和给临时数组作为下标索引
        int t = 0;
        //临时数组
        int[] tempArr = new int[arr.length];
        //遍历原数组
        for(int i = 0; i < arr.length; i++){
            //声明一个标记,并每次重置
            boolean isTrue = true;
            //内层循环将原数组的元素逐个对比
            for(int j=i+1;j<arr.length;j++){
                //如果发现有重复元素,改变标记状态并结束当次内层循环
                if(arr[i]==arr[j]){
                    isTrue = false;
                    break;
                }
            }
            //判断标记是否被改变,如果没被改变就是没有重复元素
            if(isTrue){
                //没有元素就将原数组的元素赋给临时数组
                tempArr[t] = arr[i];
                //走到这里证明当前元素没有重复,那么记录自增
                t++;
            }
        }
        //声明需要返回的数组,这个才是去重后的数组
        int[]  newArr = new int[t];
        //用arraycopy方法将刚才去重的数组拷贝到新数组并返回
        /**
         * public static void arraycopy(Object src,
         int srcPos,
         Object dest,
         int destPos,
         int length)
         src:源数组;   srcPos:源数组要复制的起始位置;
         dest:目的数组; destPos:目的数组放置的起始位置;    length:复制的长度。
         注意:src and dest都必须是同类型或者可以进行转换类型的数组.
         */

        System.arraycopy(tempArr,0,newArr,0,t);

        for(int element : newArr){
            System.out.print(element+" 我是 ");
        }
    }

希尔排序:时间复杂度O(n^1.3),注意是不稳定的排序方式

 /**
     * 希尔排序:先分组在直接插入排,由于分组以后数据基本有序,使用直接插入排序销效率最高
     * 通常分组n = 2, 或者3 ,时间复杂度大量数据下为 n ^1.3
     */
    private void shellSort() {

        int a[] = {49, 38, 65, 97, 26, 13, 27, 49, 55, 4};

        int i , j ,gap ;

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

            for ( i = gap; i < a.length ; i++) {

                for (j = i - gap ; j >= 0 && a[j] > a[j + gap] ; j-=gap) {

                    int temp = a[j];
                    a[j] = a[j+gap];
                    a[j+gap] = temp ;
                }
            }  
        }

        for(int element : a){
            System.out.print(element+" heihie ");
        }
    }

冒泡排序:时间复杂度为O(n^2)

  /**
     * 冒泡排序
     * 讲设数组长度为N。

1.比较相邻的前后二个数据,如果前面数据大于后面的数据,就将二个数据交换。

2.这样对数组的第0个数据到N-1个数据进行一次遍历后,最大的一个数据就“沉”到数组第N-1个位置。

3.N=N-1,如果N不为0就重复前面二步,否则排序完成。
  */
    private void BuddleSort() {

        int a[] = {2,1,4,3,5,2,4,7,6,8} ;

        int i , j ;

        for ( i = 0; i < a.length; i++) {

            for (j = 1; j < a.length - i; j++) {

                if (a[j -1] > a[j]){
                    int temp = a[j] ;
                    a[j] = a[j - 1];
                    a[j - 1] = temp ;
                }

            }
        }
        printSort(a);
    }

    private void printSort(int[] a) {

        for(int emplete: a){
            System.out.print("---" + emplete);
        }
    }
  1. 但当其后的数组已经有序的情况下,该方法依然会执行下去,降低效率,为此我们可以改善为:
 /**
     * 从大到小排序,如果后面的已经有序的话就不用再排序了
     */

    private void BuddleSort2() {

        int i, j ;

        int num[] = {2,1,3,4,5,6,7};

        //初始化标示用于对数组是否交换
        boolean flag = true ;

        //判断上次交换是否有改变,不改变则其后的值均有序了,跳出循环,不在遍历
        for (i = 0; i < num.length && flag; i++) {

            flag = false ;

            for (j = num.length - 1 ; j > i ; j--) {

                if (num[j - 1] > num[j]){

                    int temp = num[j-1] ;
                    num[j-1] = num[j] ;
                    num[j] = temp ;
                    //交换以后将flag设置为true,让循环继续
                    flag = true ;
                }
            }
        }
    }

简单选择排序:

  1. 不稳定,时间复杂度为O(n^2),但由于交换次数为n-1,性能上优于冒泡排序
  /**
     * 选择排序,不稳定的排序方法
     * 每一趟从待排序的记录中选出最小的元素,顺序放在已排好序的序列最后,直到全部记录排序完毕
     * 由于每次选择仅考虑某一位置上的数据情况,可能会破坏之前数据的相对位置,因此它是一种不稳定的排序方法。
     */
    private void choiceSort() {

        int num[] = {2,1,3,4,8,6,5,7};
        int i , j , min;

        for (i = 0; i < num.length - 1; i++) {
            //将初始化的i的值作为min的标示,后续判断是否相等,不相等就交换两个值
            min = i ;

            for ( j = i + 1; j < num.length; j++) {

                //如果min后面的值有小于他的,就将其数组中的索引赋值给min,在比较,知道找到最小的索引值
                if (num[min] > num[j]){
                    min = j ;
                }
            }

            if (min != i){
                //交换位置
                int temp = num[i];

                num[i] = num[min];

                num[min] = temp ;

            }
        }
        printSort(num);
    }

快速排序:时间复杂度为O(nlogn)

  1. 通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分关键字小,则分别对这两部分继续进行排序,直到整个序列有序
 /**
     *
     * @param numbers 带排序数组
     * @param low  开始位置
     * @param high 结束位置
     */
    public void quickSort(int[] numbers,int low,int high)
    {
        if(low < high) {
            int middle = quecklySort(numbers,low,high); //将numbers数组进行一分为二
            quickSort(numbers, low, middle-1);   //对低字段表进行递归排序
            quickSort(numbers, middle+1, high); //对高字段表进行递归排序
        }

    }

 /**
     * 快速排序:
     * 把整个序列看做一个数组,把第零个位置看做中轴,和最后一个比,如果比它小交换,比它大不做任何处理;
     * 交换了以后再和小的那端比,比它小不交换,比他大交换。
     * 这样循环往复,一趟排序完成,左边就是比中轴小的,右边就是比中轴大的,
     * 然后再用分治法,分别对这两个独立的数组进行排序
     *
     * * 查找出中轴(默认是最低位low)的在numbers数组排序后所在位置
     *
     * @param numbers 带查找数组
     * @param low   开始位置
     * @param high  结束位置
     * @return  中轴所在位置
     */

    private int quecklySort(int[] numbers , int low , int high) {

        int temp = numbers[low]; //数组的第一个作为中轴
        while(low < high)
        {
            while(low < high && numbers[high] >=temp)//从右向左找第一个
//小于等于基准值得index
            {
                high--;
            }
            numbers[low] = numbers[high];//比中轴小的记录移到低端
            while(low < high && numbers[low] <= temp)//从左向右找第一个
//大于等于基准值的index
            {
                low++;
            }
            numbers[high] = numbers[low] ; //比中轴大的记录移到高端
        }
        numbers[low] = temp ; //中轴记录到尾
        return low ; // 返回中轴的位置

    }


//调取的方式
 //快速排序

        int number[] = {2,1,4,5,6,3,4,2,6,8};
        quickSort(number, 0 , number.length - 1) ;

        System.out.println("我是快速排序:");
        for (int i : number) {

            Log.e("shiqiang" , i + "--");
        }

归并排序,算法复杂度O(n logn) ,稳定

  1. 将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

  2. 归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。 将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。

  3. 归并排序算法稳定,数组需要O(n)的额外空间,链表需要O(log(n))的额外空间,时间复杂度为O(nlog(n)),算法不是自适应的,不需要对数据的随机读取。

工作原理:

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

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

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

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

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

public class MergeSortTest {  

    public static void main(String[] args) {  
        int[] data = new int[] { 5, 3, 6, 2, 1, 9, 4, 8, 7 };  
        print(data);  
        mergeSort(data);  
        System.out.println("排序后的数组:");  
        print(data);  
    }  

    public static void mergeSort(int[] data) {  
        sort(data, 0, data.length - 1);  
    }  

    public static void sort(int[] data, int left, int right) {  
        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);  
    }  

    /** 
     * 将两个数组进行归并,归并前面2个数组已有序,归并后依然有序 
     *  
     * @param data 
     *            数组对象 
     * @param left 
     *            左数组的第一个元素的索引 
     * @param center 
     *            左数组的最后一个元素的索引,center+1是右数组第一个元素的索引 
     * @param right 
     *            右数组最后一个元素的索引 
     */  
    public static void merge(int[] data, int left, int center, int right) {  
        // 临时数组  
        int[] tmpArr = new int[data.length];  
        // 右数组第一个元素索引  
        int mid = center + 1;  
        // third 记录临时数组的索引  
        int third = left;  
        // 缓存左数组第一个元素的索引  
        int tmp = left;  
        while (left <= center && mid <= right) {  
            // 从两个数组中取出最小的放入临时数组  
            if (data[left] <= data[mid]) {  
                tmpArr[third++] = data[left++];  
            } else {  
                tmpArr[third++] = data[mid++];  
            }  
        }  
        // 剩余部分依次放入临时数组(实际上两个while只会执行其中一个)  
        while (mid <= right) {  
            tmpArr[third++] = data[mid++];  
        }  
        while (left <= center) {  
            tmpArr[third++] = data[left++];  
        }  
        // 将临时数组中的内容拷贝回原数组中  
        // (原left-right范围的内容被复制回原数组)  
        while (tmp <= right) {  
            data[tmp] = tmpArr[tmp++];  
        }  
    }  

    public static void print(int[] data) {  
        for (int i = 0; i < data.length; i++) {  
            System.out.print(data[i] + "\t");  
        }  
        System.out.println();  
    }  

}  

堆排序: 复杂度O(nlgn)

  1. 堆是一种重要的数据结构,为一棵完全二叉树, 底层如果用数组存储数据的话,假设某个元素为序号为i(Java数组从0开始,i为0到n-1),如果它有左子树,那么左子树的位置是2i+1,如果有右子树,右子树的位置是2i+2,如果有父节点,父节点的位置是(n-1)/2取整。分为最大堆和最小堆,最大堆的任意子树根节点不小于任意子结点,最小堆的根节点不大于任意子结点。所谓堆排序就是利用堆这种数据结构来对数组排序,我们使用的是最大堆。处理的思想和冒泡排序,选择排序非常的类似,一层层封顶,只是最大元素的选取使用了最大堆。最大堆的最大元素一定在第0位置,构建好堆之后,交换0位置元素与顶即可。堆排序为原位排序(空间小), 且最坏运行时间是O(nlgn),是渐进最优的比较排序算法。
  2. 堆排序的大概步骤如下:

    • 构建最大堆。
    • 选择顶,并与第0位置元素交换
    • 由于步骤2的的交换可能破环了最大堆的性质,第0不再是最大元素,需要调用maxHeap调整堆(沉降法),如果需要重复步骤2
public class HeapSort {  
        public static void main(String[] args) {  
            int[] array = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3 };  

            System.out.println("Before heap:");  
            ArrayUtils.printArray(array);  

            heapSort(array);  

            System.out.println("After heap sort:");  
            ArrayUtils.printArray(array);  
        }  

        public static void heapSort(int[] array) {  
            if (array == null || array.length <= 1) {  
                return;  
            }  

            buildMaxHeap(array);  

            for (int i = array.length - 1; i >= 1; i--) {  
                ArrayUtils.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) {  
                ArrayUtils.exchangeElements(array, index, largest);  

                maxHeap(array, heapSize, largest);  
            }  
        }  
    }  

工具类

public class ArrayUtils {  

        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;  
        }  
    }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值