Algorithm01-八大排序

。_饼干妹妹 提交于 2020-01-22 05:42:06

1.八大排序

排序算法大纲

2.冒泡排序

static void bubbling(int[] arr){
    final int length = arr.length;
    for (int i = 0;i < length - 1;i++){
        for (int j = 0;j < length - i - 1;j++){
            if (arr[j] > arr[j + 1]){
                int t = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = t;
            }
        }
    }
}

3.插入排序

static void insertion(int[] arr){
    final int length = arr.length;
    for (int i = 1;i < length;i++){
        //&& arr[j] < arr[j - 1],排序过后前面的数已经有序
        //arr[j] < arr[j - 1],前面已经有序,所以前面肯定没有比arr[j]大的数
        //这样减少内层循环
        for (int j = i;j > 0 && arr[j] < arr[j - 1];j--){
            if (arr[j] < arr[j - 1]){
                int t = arr[j];
                arr[j] = arr[j -1];
                arr[j - 1] = t;
            }
        }
    }
}

4.选择排序

static void selection(int[] arr){
    final int length = arr.length;
    int maxIndex = 0;
    for (int i = 0;i < length - 1;i++){
        int j = 0;
        for (;j < length - i;j++){
            if (arr[maxIndex] < arr[j]){
                maxIndex = j;
            }
        }
        j--;
        int t = arr[maxIndex];
        arr[maxIndex] = arr[j];
        arr[j] = t;
        maxIndex = 0;
    }
}

5.希尔排序

/**
     * 希尔排序-三层循环
     * date -> 0 1 2 3 4 5 6 7 8 9,gap=2
     * 要对index=1之后的所有的数据进行插入排序,不需要必须对gap间隔的一组数进行排序
     * 所以直接让i每次加1,直到小于length
     * @param array
     */
static void shellToImprove(int[] array){
    final int length = array.length;
    int gap = length / 2;
    while (gap > 0){
        for (int i = gap;i < length;i++){
            for (int j = i;j > gap - 1 && array[j] < array[j - gap];j -= gap){
                if (array[j] < array[j - gap]){
                    int t = array[j];
                    array[j] = array[j - gap];
                    array[j - gap] = t;
                }
            }
        }
        gap /= 2;
    }
}

/**
     * 希尔排序-四层循环
     * date -> 0 1 2 3 4 5 6 7 8 9,gap=2
     * 四层循环的写法,会先对2 4 6 8,在对3 5 7 9进行插入排序
     * @param arr
     */
static void shell(int[] arr){
    final int length = arr.length;
    //每次跳跃的间隔,最后一次为1
    int gap = length / 2;

    //0 1 2 3 4 5 6 7 8 9
    //控制每次跳跃的间隔,10个数5 2 1
    while (gap > 0){
        //循环间隔之间的数,如gap=5,0->5,1->6,2->7,3->8,4->9共5次
        for (int i = 0;i < gap;i++){
            //执行插入排序的逻辑,不过每次跳跃的不是1,而是gap
            for (int j = i + gap;j < length;j += gap){
                //k > gap - 1,插入排序gap=1,k>1-1=0
                for (int k = j;k > gap - 1 && arr[k] < arr[k - gap];k -= gap){
                    if (arr[k] < arr[k - gap]){
                        int t = arr[k];
                        arr[k] = arr[k - gap];
                        arr[k - gap] = t;
                    }
                }
            }
        }
        gap /= 2;
    }
}

6.快速排序

static void quick(int[] arr){
    final int length = arr.length;
    //使用LinkedList作为栈,记录要比较数据的间隔的索引
    LinkedList<Integer> stack = new LinkedList<>();
    int left = 0;
    int right = length - 1;

    int start;
    int end;

    //push进行压栈
    stack.push(left);
    stack.push(right);

    int key;
    while (!stack.isEmpty()){
        //pop出栈
        right = end = stack.pop();
        left = start = stack.pop();

        //分割数组的元素
        key = arr[left];
        //和递归的操作一致,进行key的两边数据的分割
        while (left < right){
            while (key < arr[right] && left < right){
                right--;
            }

            arr[left] = arr[right];

            while (key > arr[left] && left < right){
                left++;
            }
            arr[right] = arr[left];
        }

        arr[left] = key;
        //如果左边元素大于1,进行压栈
        if (start < left - 1){
            stack.push(start);
            stack.push(left - 1);
        }
        //如果右边元素大于1,进行压栈
        if (end > left + 1){
            stack.push(left + 1);
            stack.push(end);
        }
    }
}

static void quick(int[] arr,int left,int right){
    if (left < right){
        //position索引就是等分左右的数,所以我们在对其左、有进行排序
        int position = position(arr,left,right);
        quick(arr,left,position - 1);
        quick(arr,position + 1,right);
    }
}

static int position(int[] arr,int left,int right){
    //分割的数据,这个数据越是处于要排序的中间,排序的效率越高
    //所以我们可以通过三数取中、或者多次探测的方式保证这个数据的准确
    int key = arr[left];
    while (left < right){
        //从右边找小于等于key的数的索引
        while (arr[right] > key && left < right){
            right--;
        }
        //将小于等于key的数放在左边
        arr[left] = arr[right];

        //从左边找大于等于key的数,然后放在右边,arr[left] <= key
        while (arr[left] < key && left < right){
            left++;
        }
        arr[right] = arr[left];
    }

    //将key放在left索引的位置
    arr[left] = key;
    return left;
}

7.堆排序

static void heap(int[] arr){
    final int length = arr.length;
    for (int i = 0;i < length;i++){
        //计算出最后一个非叶子节点,length - i表示排除已经通过交换有序的数据
        int first = ((length - i) / 2) - 1;
        //从最后一个非叶子节点开始调整堆,直到根节点
        for (;first > -1;first--){
            buildHeap(arr,first,length - i);
        }

        //现在arr[0]是未排序数据中最大的值,我们与最后一个元素进行交换
        int t = arr[0];
        arr[0] = arr[length - i - 1];
        arr[length - i - 1] = t;
    }
}

 /**
     * 创建堆
     * @param arr 数组
     * @param current 当前节点
     * @param size 并非数组中所有的数都要经历重建堆的过程,已经从顶部交换的数据
     *             不需要再经历创建堆的过程
     */
static void buildHeap(int[] arr,int current,int size){
    //左子女
    int left = current * 2 + 1;
    //右子女
    int right = current * 2 + 2;

    //假定当前节点为最大
    int max = current;
    //如果当前节点的左右子女比他大,就改变最大的索引
    //判断left < size,当前节点为叶子,使得数据越界
    if (left < size){
        if (arr[max] < arr[left]){
            max = left;
        }
    }

    if (right < size){
        if (arr[max] < arr[right]){
            max = right;
        }
    }

    //最大值不是当前节点,进行交换
    if (max != current){
        int t = arr[current];
        arr[current] = arr[max];
        arr[max] = t;
        //交换之后,其左右子女有可能和最大堆的性质不符合,我们进行递归调整
        buildHeap(arr,max,size);
    }
}

8.归并排序

static void mergeSort(int[] arr,int left,int right,int[] temp){
    if (left < right){
        int mid = (left + right) / 2;
        //先进行拆分,直到只有一个元素为止
        mergeSort(arr,left,mid,temp);
        mergeSort(arr,mid + 1,right,temp);

        //每两组数据进行合并
        merge(arr,left,right,mid,temp);
    }
}

static void merge(int[] arr,int left,int right,int mid,int[] temp){
    //n用来数据在temp中的索引
    int n = left;
    //第一组数据的开始索引
    int leftStart = left;
    //第二组数据的开始索引
    int rightStart = mid + 1;

    //temp要加入的数据
    int total = right - left + 1;
    for (int i = 0;i < total;i++){
        if (leftStart > mid){
            //说明第一组数据全部添加到temp中
            temp[n] = arr[rightStart++];
        }else if (rightStart > right){
            //说明第二组数据全部添加到temp中
            temp[n] = arr[leftStart++];
        }else {
            //没有哪一组数据全部添加到temp中,所以进行两组数据的比较
            if (arr[leftStart] < arr[rightStart]){
                temp[n] = arr[leftStart++];
            }else {
                temp[n] = arr[rightStart++];
            }
        }
        n++;
    }

    //将temp中有序的数据拷贝到arr中
    for (;left <= right;left++){
        arr[left] = temp[left];
    }
}

9.桶排序

/**
     * 基数排序-先对数据的个位进行排序,得到一段相对于另一段有序的数据
     * 然后逐个对更高位进行排序
     * @param arr
     */
static void radixSort(int[] arr){
    //记录每次数据要整除的数字,如1 10 100
    int n = 1;
    //通过一个二维数字保存每一个位置有序的数据
    //相当于一个桶,一共有十个
    int[][] arrs = new int[10][arr.length];
    //记录arrs每一个桶中数据的个数
    int[] count = new int[10];
    int temp;
    int num;
    int c;
    while (n < 20){
        //将arr中的数据放入相应的桶中
        //如在对个位进行操作的时候,21,放入3个桶中
        for (int i = 0;i < arr.length;i++){
            //得到数据相应的位置的数据
            temp = (arr[i] / n) % 10;
            //获取当前位置的桶已经保存的数据的个数
            num = count[temp];
            arrs[temp][num] = arr[i];
            count[temp] = num + 1;
        }

        num = 0;
        c = 0;
        for (int i = 0;i < 10;i++){
            temp = 0;
            //count[num] == 0说明这个桶并没有保存数据
            if (count[num] != 0){
                //按照桶的索引将数据考入arr中
                for (;temp < count[num];temp++){
                    arr[c++] = arrs[num][temp];
                }
            }
            //清空原来每一个桶中数据的个数,使得桶可以重复使用
            count[num] = 0;
            num++;
        }
        n *= 10;
    }
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!