面試常見排序演算法
阿新 • • 發佈:2019-01-01
本文先給一個表格總結各個排序演算法的時間複雜度、空間複雜度、穩定性等。然後重點介紹快速排序和堆排序兩個面試過程中必問的排序,最後再介紹其他排序演算法。
一、常見排序演算法總結
穩定性:假定在待排序的記錄序列中,存在多個具有相同的關鍵字的記錄,若經過排序,這些記錄的相對次序保持不變,即在原序列中,ri=rj,且ri在rj之前,而在排序後的序列中,ri仍在rj之前,則稱這種排序演算法是穩定的;否則稱為不穩定的。
注意:堆排序和快速排序都是不穩定的,堆排序的平均情況和最好最壞情況時間複雜度都是O(nlogn)。
快速排序平均情況和最好情況時O(nlogn),最壞情況時O(n2),面試過程中常問。
二、快速排序演算法總結
2.1、快排的基本思想
- 先從數列中取出一個數作為基準數
- 分割槽過程,將小於或等於基準數的放到左邊,將大於基準數的放到右邊。
- 再對第二步得到的左右兩個區間重複1、2過程,直到各區間只有一個數。
例項介紹
有以下一組數:
72 | 6 | 57 | 88 | 60 | 42 | 83 | 73 | 48 | 85 |
---|
1. 選取基準數:原則上基準數要隨機選取,但是我們這邊的資料可以認為是隨機的,所以我們每次的基準數都選取第一個數。這裡為72.
2. 分割槽。分為如下左右兩區:
6 | 57 | 60 | 42 | 48 | 72 | 88 | 83 | 73 | 85 |
---|
3. 對左右兩區重複1、2步,截止到每個區只有一個數。
左區重複,選基準數、分割槽過程
6 | 57 | 60 | 42 | 48 |
---|
右區
88 | 83 | 73 | 85 |
---|
2.2、快排的時間複雜度和空間複雜度分析
時間複雜度
快速排序的時間複雜度依賴於劃分是否平衡。
最壞情況分析:O(n^2)
每次劃分的時候左右兩區間分別包含了n-1個元素和0個元素最好情況分析:O(nlogn)
每次劃分的時候左右兩區間的元素個數幾乎相等。
2.3、快排的程式編寫
int * quickSort(int* A, int n) {
// write code here
//入參校驗
if(A==NULL || n<=0){
cout<<"入參不合法"<<endl;
return NULL;
}
//快排
coreQuickSort(A, 0, n-1);
return A;
}
/*
* 快排,裡面遞迴呼叫,遞迴截止條件為left>=right
*/
void coreQuickSort(int* A, int left, int right){
if(left<right){
int mid=parition(A, left, right);
coreQuickSort(A, left, mid-1);
coreQuickSort(A, mid+1, right);
}
}
/**
* 一次劃分
*@return 一次劃分完後的中間索引
*/
int parition(int* A, int left, int right){
int key=A[right];
int lessNumIndex=left-1;
for(int search=left; search<=right; search++){
if(A[search]<=key){
lessNumIndex++;
swap(A, lessNumIndex, search);
}
}
return lessNumIndex;
}
/**
* 交換函式
*/
void swap(int* A, int index1, int index2){
int tmp=A[index1];
A[index1]=A[index2];
A[index2]=tmp;
}
三、堆排序演算法總結
3.1、堆排序的思想
堆:以最小堆為例,根節點不大於左右子節點。
堆排序:先將陣列初始化為最小堆,然後每次取出堆頂的元素,取完之後對堆進行維護,維護其為最小堆。這樣取出來的元素就會是從小到大排列的。
3.2、堆排序的時間複雜度和空間複雜度分析
時間複雜度:
時間複雜度是O(n*logn),對陣列初始化為堆的時候,時間複雜度為O(n),取完堆頂元素後,需要維護堆,每次維護堆的時間複雜度為O(logn),共需要N-1次維護堆的操作。
所以O(N)+(N-1)*O(logN)=O(N*logN)
3.3、堆排序程式編寫
int* heapSort(int* A, int n) {
int lastPosi=n-1;
maxHeapBuild(A, lastPosi); //建最大堆
while(lastPosi>=1){ //維護最大堆
swap(A, 0, lastPosi);
lastPosi=lastPosi-1;
heapifyMax(A, 0, lastPosi);
}
return A;
}
//建立最大堆
void maxHeapBuild(int* A, int lastPosi){
for(int i=(lastPosi-1)/2; i>=0; i--){
heapifyMax(A, i, lastPosi);
}
}
//堆下沉,建立最大堆和維護堆的時候都需要的過程
void heapifyMax(int* A, int posi, int lastPosi){
int maxLR=2*posi+1;
while(maxLR<=lastPosi){
if( maxLR < lastPosi && A[maxLR+1]>A[maxLR]){
maxLR++;
}
if(A[maxLR] <= A[posi]){
break;
}
else{
swap(A, posi,maxLR);
posi=maxLR;
maxLR=2*posi+1;
}
}
}
//交換
void swap(int* A, int index1, int index2){
int tmp=A[index1];
A[index1]=A[index2];
A[index2]=tmp;
}