要点
时间复杂度–平均情况:O(nlogn);最好情况:O(nlogn);最坏情况O(n
2)。辅助空间O(logn)~O(n)。快速排序是一种不稳定的排序方式。快排的基本思想:定义一个基准值将待排记录分割为独立的两部分,其中一部记录的关键字均比另一部分的关键字小,再分别对这两部分记录继续进行排序,直到每部分记录只有一个关键字。每一趟排序都只能确定基准值的位置。方式二的交换次数只有方式一的1/2。快速排序的优化:
优化选取基准值:三数取中,九数取中…优化不必要的交换(采用替换而不是交换的方式)优化递归操作优化小数组时的排序方案:如果数组非常小,其实快速排序反而不如直接插入排序来得更好(直接插入排序是简单排序中性能最好的)。其原因在于快速排序用到了递归操作。当数组长度不大于X(有认为X=7比较合适,也有认为50更合理,实际应用可适当调整),就用直接插入排序,这样就能保证最大化地利用两种排序的优势来完成排序工作。
基本思路(一趟排序)
方式一:
定义一个基准值(分界值)-- 数组开始位置为基准值定义两个指针start和end分别指向数组两端end指针向前遍历(从右往左)直到找到一个比基准值小的关键字(或与start指针相遇),则基准值和当前end指针指向的关键字交换位置,交换后当前end指向基准值start指针向后遍历(从左往右)直到找到一个比基准值大的关键字(或与end指针相遇),则基准值和当前start指针指向的关键字交换位置,交换后当前start指向基准值重复步骤3和步骤4,若出现start指针和end指针相遇的情形(start==end),则返回基准值所在位置(start或end),此时排序完成。基准值已将待排记录分割为独立的两部分,其中一部记录的关键字均比另一部分的关键字小。
public int sort(int[] nums
, int start
, int end
) {
int base
= nums
[start
];
while (start
< end
) {
while (start
< end
&& nums
[end
] >= base
)
end
--;
swap(nums
, start
, end
);
while (start
< end
&& nums
[start
] <= base
)
start
++;
swap(nums
, start
, end
);
}
return start
;
}
方式二:
定义一个基准值(分界值)-- 数组开始位置为基准值定义两个指针start和end分别指向数组两端end指针向前遍历(从右往左)直到找到一个比基准值小的关键字(或与start指针相遇)start指针向后遍历(从左往右)直到找到一个比基准值大的关键字(或与end指针相遇)交换start指针和end指针指向的关键字重复步骤3、步骤4和步骤5,若出现start指针和end指针相遇的情形,则start/end指针指向的关键字与基准值(数组开始位置)进行交换并返回交换后基准值的位置(start或end),完成这次排序。基准值已将待排记录分割为独立的两部分,其中一部记录的关键字均比另一部分的关键字小。
public int sort(int[] nums
, int start
, int end
) {
int base
= nums
[start
], baseKey
= start
;
while (start
< end
) {
while (start
< end
&& nums
[end
] >= base
)
end
--;
while (start
< end
&& nums
[start
] <= base
)
start
++;
if (start
< end
) {
swap(nums
, start
, end
);
} else {
swap(nums
, baseKey
, end
);
}
}
return start
;
}
实现快速排序
public void quickSort(int[] nums
, int start
, int end
) {
int baseKey
;
if (start
< end
) {
baseKey
= sort(nums
, start
, end
);
quickSort(nums
, start
, baseKey
- 1);
quickSort(nums
, baseKey
+ 1, end
);
}
}
补充:交换方法
public void swap(int[] nums
, int a
, int b
) {
int temp
;
temp
= nums
[a
];
nums
[a
] = nums
[b
];
nums
[b
] = temp
;
}
快速排序优化
public class QuickSort {
public void quickSort(int[] nums
, int start
, int end
) {
int baseKey
;
if ((end
- start
) > MAX_LENGTH_INSERT_SORT
) {
while (start
< end
) {
baseKey
= sort(nums
, start
, end
);
quickSort(nums
, start
, baseKey
- 1);
start
= baseKey
+ 1;
}
} else {
insertSort(nums
);
}
}
public int sort(int[] nums
, int start
, int end
) {
int base
;
int mid
= (start
+ end
) / 2;
if (nums
[start
] > nums
[end
])
swap(nums
, start
, end
);
if (nums
[mid
] > nums
[end
])
swap(nums
, mid
, end
);
if (nums
[mid
] > nums
[start
])
swap(nums
, start
, mid
);
base
= nums
[start
];
while (start
< end
) {
while (start
< end
&& nums
[end
] >= base
)
end
--;
nums
[start
] = nums
[end
];
while (start
< end
&& nums
[start
] <= base
)
start
++;
nums
[end
] = nums
[start
];
}
nums
[start
] = base
;
return start
;
}
public void swap(int[] nums
, int a
, int b
) {
int temp
;
temp
= nums
[a
];
nums
[a
] = nums
[b
];
nums
[b
] = temp
;
}
}
补充:直接插入排序[了解一下]
public void insertSort(int[] nums
) {
int guard
, i
, j
;
for (i
= 1; i
< nums
.length
; i
++) {
if (nums
[i
] < nums
[i
- 1]) {
guard
= nums
[i
];
for (j
= i
- 1; j
>= 0 && nums
[j
] > guard
; j
--)
nums
[j
+ 1] = nums
[j
];
nums
[j
+ 1] = guard
;
}
}
}