文章来源——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;
}