Java——排序(冒泡排序,选择排序、插入排序,快速排序)

冒泡排序

排序思想

就像“冒泡泡”一样,从头开始,两个两个数作比较,将两个数中较大(较小)的数向后移,再比较下面两个数,依次将较大(较小)的数向后移,最终,将一组数中最大(最小)的数,移动到最后面,再从头开始,移下一个数
下面是一个栗子:
要排序数组(升序):{4,2,7,3,1}
————————————
第一趟(交换四次):

  • 第一次:4与2比较,4大于2,交换两个数——{2,4,7,3,1}
  • 第二次:4与7比较,7大于4,不交换位置——{2,4,7,3,1}
  • 第三次:7与3比较,7大于3,交换两个数——{2,4,3,7,1}
  • 第四次:7与1比较,7大于1,交换两个数——{2,4,3,1,7}

第二趟(交换3次):

  • 第一次:2与4比较,4大于2,不交换位置——{2,4,3,1,7}
  • 第二次:4与3比较,4大于3,交换两个数——{2,3,4,1,7}
  • 第三次:4与1比较,4大于1,交换两个数——{2,3,1,4,7}

第三趟(交换两次):

  • 第一次:2与3比较,3大于2,不交换位置——{2,3,1,4,7}
  • 第二次:3与1比较,3大于1,交换两个数——{2,1,3,4,7}

第四趟(交换一次):

  • 第一次:2与1比较,2大于1,交换两个数——{1,2,3,4,7}

————————————
根据上面的栗子可以得出有n个数字要进行排序总共要进行 n - 1 趟,每 i 趟要排序 n - i - 1 次

排序优点

每进行一趟排序,就会少比较一次,因为每进行一趟排序都会找出一个较大值。如上例:第一趟比较之后,排在最后的一个数一定是最大的一个数,第二趟排序的时候,只需要比较除了最后一个数以外的其他的数,同样也能找出一个最大的数排在参与第二趟比较的数后面,第三趟比较的时候,只需要比较除了最后两个数以外的其他的数,以此类推……也就是说,每进行一趟比较,每一趟少比较一次,一定程度上减少了算法的量。

时间复杂度

冒泡排序的时间复杂度为O(N^2)

空间复杂度

冒泡排序的空间复杂度为O(1)

实现代码

/**
 * 冒泡排序(升序)
 * @author LXY
 * @email [email protected]
 * @date 2018/8/18 16:10
 */
public class BubbleSort {
    public static void bubbleSort(int[] arr)
    {
        if(arr == null || arr.length == 0)
        {
            return;
        }
        for(int i = 0;i < arr.length - 1;i++)
        {
            for(int j = 0;j < arr.length - 1 - i;j++)
            {
                if(arr[j] > arr[j + 1])
                {
                    swap(arr,j,j + 1);
                }
            }
        }
    }

    private static void swap(int[] arr, int j, int i) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

    public static void main(String[] args) {
        int[] arr = {4,2,7,3,1,8,9,5};
        bubbleSort(arr);
        for(int i:arr)
        {
            System.out.print(i + " ");
        }
    }
}

选择排序

排序思想

每一趟从待排序的记录中选出最小的元素,顺序放在已排好序的序列最后,直到全部记录排序完毕。也就是:每一趟在n-i+1(i=1,2,…n-1)个记录中选取关键字最小的记录作为有序序列中第i个记录。
下面是一个栗子:
要排序数组(升序):{4,2,7,3,1}
————————————
第一趟:

  • 将数组中最小的元素1与第一个元素4交换——{1,2,7,3,4}

第二趟:

  • 将除了第一个元素外的最小元素2,与第二个位置的元素2交换(此处就是2,因此不用交换)——{1,2,7,3,4}

第三趟:

  • 将除了前两个元素外的最小元素3与第三个位置的元素7交换——{1,2,3,7,4}

第四趟:

  • 将除了前三个元素外的最小元素4与第四个位置的元素7交换——{1,2,3,4,7}

————————————

时间复杂度

选择排序的时间复杂度为O(N^2)

空间复杂度

选择排序的空间复杂度为O(1)

代码实现

package selectSort;

/**
 * 选择排序(升序)
 * @author LXY
 * @email [email protected]
 * @date 2018/8/18 16:31
 */
public class SelectSort {
    public static void selectSort(int[] arr)
    {
        if(arr == null || arr.length == 0)
        {
            return;
        }
        for(int i = 0;i < arr.length - 1;i++)
        {
            int index = i;
            for(int j = i + 1;j < arr.length;j++)
            {
                if(arr[j] < arr[index])
                {
                    swap(arr,j,index);
                }
            }
        }
    }
    private static void swap(int[] arr, int j, int i) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

    public static void main(String[] args) {
        int[] arr = {4,2,7,3,1,8,9,5};
        selectSort(arr);
        for(int i:arr)
        {
            System.out.print(i + " ");
        }
    }
}

插入排序

排序思想

插入排序就像是玩扑克牌时要把牌放到手中以有的牌中一样,像下面这张图一样,原本手中的牌是{2,4,5,10},但是抽到了一张7,此时应该怎么办?
将牌从右向左看,7比10小,比5大,那么正好就放到这里,那么为什么不继续向前面比较了?是因为牌本身是有顺序的

我盗图了
图片是盗的
下面是一个情况最坏的栗子:
要排序数组(升序):{5,4,3,2}
————————————
第一次插入:

  • 将位置1(数组从位置0开始算起,并且默认位置0,即第一个元素已经插入完成)的元素4开始与它之前的元素5进行比较,发现4比5小,将4和5交换{4,5,3,2}

第二次插入:

  • 将位置2的元素3与它之前的元素5进行比较,发现3比5小,将3和5交换{4,3,5,2}
  • 将位置1的元素3与它之前的元素4进行比较,发现3比4小,将3和4交换{3,4,5,2}

第三次插入:

  • 将位置3的元素2与它之前的元素5进行比较,发现2比5小,将2和5交换{3,4,2,5}
  • 将位置2的元素2与它之前的元素4进行比较,发现2比4小,将3和5交换{3,2,4,5}
  • 将位置1的元素2与它之前的元素3进行比较,发现2比3小,将2和3交换{2,3,4,5}

————————————

时间复杂度

插入排序的时间复杂度为O(N^2)

空间复杂度

插入排序的空间复杂度为O(1)

代码实现

package insertSort;

/**
 * 插入排序(升序)
 * 该种方法需要不断地进行交换赋值,这样会产生时间地浪费
 * @author LXY
 * @email [email protected]
 * @date 2018/8/18 16:48
 */
public class InsertSort {
    public static void insertSort(int[] arr)
    {
        if(arr == null || arr.length == 0)
        {
            return;
        }
        //默认第一个位置的元素摆放完毕,从第二个位置的元素开始
        for(int i = 1;i < arr.length;i++)
        {
            for(int j = i;j > 0 && arr[j] < arr[j - 1];j--)
            {
                swap(arr,j,j - 1);
            }
        }
    }
    private static void swap(int[] arr, int j, int i) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

    public static void main(String[] args) {
        int[] arr = {4,2,7,3,1,8,9,5};
        insertSort(arr);
        for(int i:arr)
        {
            System.out.print(i + " ");
        }
    }
}
package insertSort;

/**
 * 插入排序(升序)
 * 该种方法是上面那种方法地改进版本,不需要来回地交换元素
 * @author LXY
 * @email [email protected]
 * @date 2018/8/18 16:48
 */
public class InsertSort2 {
    public static void insertSort(int[] arr)
    {
        if(arr == null || arr.length == 0)
        {
            return;
        }
        //默认第一个位置的元素摆放完毕,从第二个位置的元素开始
        for(int i = 1;i < arr.length;i++)
        {
            int j;
            int tmp = arr[i];
            for(j = i;j > 0 && arr[j - 1] > tmp;j--)
            {
                arr[j] = arr[j - 1];
            }
            arr[j] = tmp;
        }
    }
    private static void swap(int[] arr, int j, int i) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

    public static void main(String[] args) {
        int[] arr = {4,2,7,3,1,8,9,5};
        insertSort(arr);
        for(int i:arr)
        {
            System.out.print(i + " ");
        }
    }
}

快速排序

排序思想

以一个值为基准(通常以第一个值),然后将比他小的数移到它左边,比他大的数移到右边
详细见博客:http://developer.51cto.com/art/201403/430986.htm

时间复杂度

  • 快速排序的时间复杂度平均为O(N*logN)
    在最好情况下,每次划分所取的基准都是当前无序区的”中值”记录,划分的结果是基准的左、右两个无序子区间的长度大致相等。总的关键字比较次数:O(N*logN)

  • 快速排序的时间复杂度最坏为O(N^2)
    最坏情况是每次划分选取的基准都是当前无序区中关键字最小(或最大)的记录,划分的结果是基准左边的子区间为空(或右边的子区间为空),而划分所得的另一个非空的子区间中记录数目,仅仅比划分前的无序区中记录个数减少一个。因此,快速排序必须做nN1次划分,第i次划分开始时区间长度为N-i+1,所需的比较次数为N-i(1≤i≤N-1),故总的比较次数达到最大值:Cmax= N*(N-1)/2=O(N^2)

空间复杂度

  • 快速排序的空间复杂度为O(logN)
    快速排序在系统内部需要一个栈来实现递归。若每次划分较为均匀,则其递归树的高度为O(logN),故递归后需栈空间为O(logN)

代码实现

递归实现
package quickSort;

/**
 * 快速排序(递归实现)
 * @author LXY
 * @email [email protected]
 * @date 2018/8/18 17:28
 */
public class QuickSort {
    public static void quickSort(int[] arr,int start,int end)
    {
        if(arr == null || arr.length == 0 || start > end)
        {
            return;
        }
        int key = quickSortHelp(arr,start,end);
        quickSort(arr,start,key - 1);
        quickSort(arr,key + 1,end);
    }

    //找中间节点位置的辅助函数
    private static int quickSortHelp(int[] arr, int start, int end) {
        if(arr == null || arr.length == 0 || start > end)
        {
            return -1;
        }
        int keyValue = arr[start];
        while (start < end)
        {
            while (start < end && arr[end] > keyValue)
            {
                //找到第一个小于keyValue的元素
                end--;
            }
                //交换两个元素
                arr[start] = arr[end];
            while (start < end && arr[start] <= keyValue)
            {
                //找到第一个大于keyValue的元素
                start++;
            }
                arr[end] = arr[start];
        }
        arr[start] = keyValue;
        return start;
    }

    public static void main(String[] args) {
        int[] arr = {4,2,7,3,1,8,9,5};
        quickSort(arr,0,arr.length - 1);
        for(int i:arr)
        {
            System.out.print(i + " ");
        }
    }
}
非递归实现
package quickSort;

import java.util.Stack;

/**
 * 快速排序(非递归实现)
 * @author LXY
 * @email [email protected]
 * @date 2018/8/18 17:28
 */
public class QuickSortRec {
    public static void quickSort(int[] arr,int start,int end)
    {
        if(arr == null || arr.length == 0 || start > end)
        {
            return;
        }
        Stack<Integer> stack = new Stack<>();
        if(start < end)
        {
            stack.push(end);
            stack.push(start);
            while (!stack.isEmpty())
            {
                int left = stack.pop();
                int right = stack.pop();
                int key = quickSortHelp(arr,left,right);
                if(left < key)
                {
                    //出栈元素在标记位置左边
                    //将标记位置和刚才出栈的元素依次入栈
                    stack.push(key - 1);
                    stack.push(left);
                }
                if(right > key)
                {
                    //出栈元素在标记位置右边
                    //将刚才出栈的元素和标记位置的元素依次入栈
                    stack.push(right);
                    stack.push(key + 1);
                }
            }
        }
    }

    //找中间节点位置的辅助函数
    private static int quickSortHelp(int[] arr, int start, int end) {
        if(arr == null || arr.length == 0 || start > end)
        {
            return -1;
        }
        int keyValue = arr[start];
        while (start < end)
        {
            while (start < end && arr[end] > keyValue)
            {
                //找到第一个小于keyValue的元素
                end--;
            }
                //交换两个元素
                arr[start] = arr[end];
            while (start < end && arr[start] <= keyValue)
            {
                //找到第一个大于keyValue的元素
                start++;
            }
                arr[end] = arr[start];
        }
        arr[start] = keyValue;
        return start;
    }

    public static void main(String[] args) {
        int[] arr = {4,2,7,3,1,8,9,5};
        quickSort(arr,0,arr.length - 1);
        for(int i:arr)
        {
            System.out.print(i + " ");
        }
    }
}

猜你喜欢

转载自blog.csdn.net/L_X_Y_HH/article/details/81812510
今日推荐