记录:列表排序(二)

文章来源——JAVA程序员成功面试秘籍

  1. 冒泡排序。效率低,最坏情况性能是O(n*n),最好情况性能是O(n)。
//伪代码
for i between 0 and (array length-2)
    if(array[i+1]<array[i])
        交换array[i]和array[i+1]
一直重复,直到在一次完整的迭代中没有元素被交换

//冒泡排序例子
public void bubbleSort(int[] numbers){
    boolean numbersSwitched;
    do{
        numberSwitched = false;
        for(int i = 0; i < numbers.length - 1 ; i++){
            if(numbers[i+1] < numbers[i]){
                int temp = numbers[i+1];
                numbers[i+1] = numbers[i];
                numbers[i] = temp; 
                numbersSwitched = true;
            }
        }
    }while(numbersSwitched);
}
    2. 插入排序算法返回值是一个新的List,而且是链表LinkedList的实例。链表类型的列表在中间插入元素比较 高效,而ArrayList内部实现的是数组,如果从表头或中间插入要不断地移动元素,代价高。最坏情况复杂度为O(n*n),最好情况复杂度为O(n)。
//伪代码
给定列表l和新列表nl
for each element originallistelemin list l:
    for each element newlistelemin list nl:
        if(originallistelem < newlistelem):
            将originallistelem插入nl中在newlistelem之前的位置
        else:
            继续下一个元素
    if originallistelem没有被插入:
        插入nl的尾端

//插入排序实例
public static List<Integer> insertSort(final List<Integer> numbers){
    final List<Integer> sortedList = new LinkedList<>();
    originalList: for (Integer number : numbers){
        for(int i=0; i<sortedList.size(); i++){
            if(number < sortedList.get(i)){
                sortedList.add(i,number);
                continue originalList;
            }
        }
        sortedList.add(sortedList.size(),number);
    }
    return sortedList;
}

    3. 快速排序(quicksort)算法这个算法是递归的。性能远高于冒泡和插入排序,最坏情况的复杂度任然是O(n*n),平均复杂度是O(n log n)。基础情形是列表里有0个和1个元素,此时直接返回。第二部分是从列表中任意挑选出一个元素为枢轴(pivot),剩下的元素分两组:一组中的元素比枢轴小,另一组大于等于枢轴。然后针对这两个列表调用此方法,返回的结果是两个排好序的列表。

//伪代码
method quicksort(list l):
    if l.size < 2:
        return l
    let pivot = l(0)
    let lower = new list
    let higher = new list
    for each element e in between l(0) and the end of the list:
        if e < pivot:
            add e to lower
        else add e to higher
    let sortedlower = quicksort(lower)
    let sortedhigher = quicksort(higher)
    return sortedlower + pivot + sortedhigher

//快速排序实例
public static List<Integer> quicksort(List<Integer> numbers){
    if(numbers.size() < 2){
        return numbers;
    }
    final Integer pivot = numbers.get(0);//取第一个元素为枢轴,亦可取其他元素
    // 提取出的枢轴是否不放入这两个列表中?
    final List<Integer> lower = new ArrayList<>();
    final List<Integer> higher = new ArrayList<>();
    for(int i = 1; i <numbers.size(); i++){
        if(numbers.get(i) < pivot){
            lower.add(numbers.get(i));
        }else{
            higher.add(numbers.get(i));
        }
    }
    // 每一次对列表的分割和后续的递归调用都是互相无关的,因此可以并行执行
    final List<Integer> sorted = quicksort(lower);
    sorted.add(pivot);
    sorted.addAll(quicksort(higher));
    return sorted;
} 

    4. 归并排序算法又是一个分而治之(divide-and-conquer)的算法,将列表分为两个子列表,分别对这两个列表进行排序,然后将两个子列表归并为一个列表。算法复杂度为O(n log n),即每一个合并操作的复杂度为O(n),而每一次递归调用都只针对给定列表的一半进行操作。List类的subList方法接受两个参数:from 和 to,其中from 是包括的,to 是不包括的。

//伪代码
method mergesort(list l):
    if list.size < 2:
        return l
    let middleIndex = l.size / 2 
    let leftList = elements between l(0) and l(middleIndex - 1)
    let rightList = elements between l(middleIndex) and l(size - 1)
    let sortedLeft = mergesort(leftList)
    let sortedRight = mergesort(rightList)
    return merge(sortedLeft, sortedRight)
method merge(list l, list r)
    let leftPtr = 0
    let rightPtr = 0
    let toReturn = new list
    while (leftPtr < l.size and rightPtr < r.size):
        if(l(leftPtr) < r(rightPtr)):
            toReturn.add(l(leftPtr)):
            leftPtr++
        else:
            toReturn.add(r(rightPtr))
            rightPtr++
    while(leftPtr < l.size):
        toReturn.add(l(leftPtr))
        leftPtr++
    while(rightPtr < r.size):
        toReturn.add(r(rightPtr))
        rightPtr++
    return toReturn

//归并排序实例
public static List<Integer> mergesort(final List<Integer> values){
    if(values.size() < 2){
        return values;
    }
    final List<Integer> leftHalf = values.subList(0, values.size() / 2);
    final List<Integer> rightHalf = values.subList(values.size() / 2, values.size());
    //递归拆分排序合并
    return merge(mergesort(leftHalf), mergesort(rightHalf));
}
//merge方法:合并两个已排好序的列表
private static List<Integer> merge(final List<Integer> left, final List<Integer> right){
    int leftPtr = 0;
    int rightPtr = 0;
    final List<Integer> merged = new ArrayList<>(left.size() + right.size());
    //选择两个指针指向的值中最小的那个值,将这个值添加到结果列表中,然后递增相应的指针。有一个指针到达其对应的列表尾端时,将另一个列表后面剩下的部分全部添加到结果列表中。
    while(leftPtr < left.size() && rightPtr < right.size()){
        if(left.get(leftPtr)<right.get(rightPtr)){
            merged.add(left.get(leftPtr));
            leftPtr++;
        }else{
            mergeed.add(right.get(rightPtr));
            rightPtr++;
        }
    }
    //下面两个while循环的条件中有一个会立即返回假,因为在前面的循环中有一个子列表的元素会全部消耗光
    while(leftPtr < left.size()){
        merged.add(left.get(leftPtr));
        leftPtr++;
    }
    while(rightPtr < right.size()){
        merged.add(right.get(rightPtr));
        rightPtr++;
    }
    return merged;
} 

猜你喜欢

转载自blog.csdn.net/ilaria_zhong/article/details/80719339