文章来源——JAVA程序员成功面试秘籍
- 冒泡排序。效率低,最坏情况性能是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; }