資料結構 排序(直接插入排序、起泡(冒泡)排序、簡單選擇排序、快速排序、堆排序、基數排序)
這是目錄
需要用到的結構的定義
template<typename KeyType, typename InfoType>
struct RedType
{
KeyType key;
InfoType otherinfo;
};
enum Status { ERROR = 0, OK = 1 };
template<typename ElemType>
struct SqList
{
ElemType data[MAX_LIST_SIZE + 1];
int length;
};
template<typename KeyType, typename InfoType>
using HeapType = SqList<RedType<KeyType, InfoType>>;
template<typename KeysType, typename InfoType>
struct SLCell
{
KeysType keys[MAX_NUM_OF_KEY];
InfoType otheritems;
int next;
};
template<typename KeysType, typename InfoType>
struct SLList
{
SLCell<KeysType, InfoType>* r;
int keynum, recnum;
};
using ArrType = int[RADIX];
直接插入排序
將資料分為兩個部分,前面是已排好序的部分,後面是未排好序的部分。開始時假設第一個元素是已排好序的,之後每一輪都將未排好序的部分的第一個元素,與已排好序的部分的每一個元素,從後往前依次比較,不符合要求的元素就向後移一個位置,直到找到正確的位置。
時間複雜度(平均):O(n^2)
時間複雜度(最壞):O(n^2)
空間複雜度:O(1)
template<typename KeyType,typename InfoType>
void insertSort(SqList<RedType<KeyType, InfoType>>& L)//直接插入排序
{
for (int i = 2; i <= L.length; i++)
{
if (L.data[i].key < L.data[i - 1].key)
{
L.data[0] = L.data[i];//哨兵節點用來記錄本輪資料
L.data[i] = L.data[i - 1];
int j;
for (j = i - 2; L.data[0].key < L.data[j].key; j--)
L.data[j + 1] = L.data[j];
L.data[j + 1] = L.data[0];
}
}
}
起泡排序(氣泡排序)
每一趟從頭到尾依次將相鄰的兩個元素進行比較,並根據要求交換位置,每一趟排序都可以確定一個元素到最後一個位置,直到所有元素都確定完成。同時,如果某一趟沒有發生交換,則可以認為已經排好序了,此時無需繼續排序,所以可以設定一個標誌位,用於標誌本輪是否發生交換,若未發生交換則可以直接退出排序。
時間複雜度(平均):O(n^2)
時間複雜度(最壞):O(n^2)
空間複雜度:O(1)
穩定性:穩定
template<typename KeyType, typename InfoType>
void bubbleSort(SqList<RedType<KeyType, InfoType>>& L)//起泡排序
{
bool exchange = true;//標誌本輪是否發生交換
for (int i = 0; i < L.length && exchange; i++)//沒發生交換可以直接退出
{
exchange = false;//預設沒交換
for (int j = 1; j < L.length - i; j++)
{
if (L.data[j].key > L.data[j + 1].key)
{
exchange = true;//發生交換
RedType<KeyType, InfoType> t;
t = L.data[j];
L.data[j] = L.data[j + 1];
L.data[j + 1] = t;
}
}
}
}
簡單選擇排序
將資料分為兩個部分,前面是已排好序的部分,後面是未排好序的部分。從頭開始,每一次遍歷未排好序的部分的所有元素,選擇其中最小的元素,將其放到已排好序的部分的最後。
時間複雜度(平均):O(n^2)
時間複雜度(最壞):O(n^2)
空間複雜度:O(1)
穩定性:穩定
template<typename KeyType, typename InfoType>
int selectMinKey(SqList<RedType<KeyType, InfoType>>& L, int i)//選擇從i開始到最後的最小關鍵字
{
int min = i;
for (int j = i + 1; j <= L.length; j++)
if (L.data[j].key < L.data[min].key)
min = j;
return min;
}
template<typename KeyType, typename InfoType>
void selectSort(SqList<RedType<KeyType, InfoType>>& L)//簡單選擇排序
{
for (int i = 1; i < L.length; i++)//從頭開始遍歷
{
int min = selectMinKey(L, i);//尋找最小關鍵字
if (min != i)
{//交換i與最小關鍵字的元素
RedType<KeyType, InfoType> t;
t = L.data[min];
L.data[min] = L.data[i];
L.data[i] = t;
}
}
}
快速排序
先確定一個樞軸,將所有資料分為兩個部分,左邊的比樞軸小,右邊的比樞軸大,然後再對左右兩個部分同樣進行快速排序,直到序列有序。首先選擇第一個元素作為樞軸,然後從最後一個元素開始向前,依次將每一個元素與樞軸進行比較,如果比樞軸小,則將該元素覆蓋第一個元素,再從第一個元素向後,依次將每一個元素與樞軸進行比較,如果比第一個元素大,則將該元素覆蓋上一步確定的元素,然後再從被覆蓋的元素開始向前進行搜尋與覆蓋。以此類推,每一次都將不符合要求的元素覆蓋另一邊的元素,然後從另一邊被覆蓋的元素繼續向前或向後搜尋,直到兩邊相遇,相遇的位置再由樞軸覆蓋,至此完成了一趟快速排序,然後繼續對樞軸左右兩邊分別同樣進行快速排序。
時間複雜度(平均):O(n logn)
時間複雜度(最壞):O(n^2)
空間複雜度:O(logn)
穩定性:不穩定
template<typename KeyType, typename InfoType>
int partition(SqList<RedType<KeyType, InfoType>>& L, int i, int j)//調整元素關於樞軸的位置並返回樞軸座標
{
L.data[0] = L.data[i];//哨兵節點記錄樞軸資料
KeyType pivotKey = L.data[i].key;//取最左邊為樞軸
while (i < j)//從左右向中間掃描
{
while (i < j && L.data[j].key >= pivotKey)//因為取最左邊為樞軸,所以要從最右邊開始
j--;
L.data[i] = L.data[j];
while (i < j && L.data[i].key <= pivotKey)
i++;
L.data[j] = L.data[i];
}
L.data[i] = L.data[0];//樞軸位置
return i;
}
template<typename KeyType, typename InfoType>
void QSort(SqList<RedType<KeyType, InfoType>>& L, int i, int j)//遞迴進行快速排序
{
if (i < j)
{
int pivotLoc = partition(L, i, j);//找到樞軸
QSort(L, i, pivotLoc - 1);//樞軸左邊快速排序
QSort(L, pivotLoc + 1, j);//樞軸右邊快速排序
}
}
template<typename KeyType, typename InfoType>
void quickSort(SqList<RedType<KeyType, InfoType>>& L)//快速排序
{
QSort(L, 1, L.length);
}
堆排序
首先要建堆,從有孩子的元素中的最後一個元素開始到第一個元素進行建堆(將該元素與自己的孩子進行比較,若不符合要求,則將自己與孩子交換,然後繼續與孩子的孩子比較,直到確定該元素的位置)。建堆完成之後,將堆分成兩部分,前面是未交換過的部分,後面是已交換過的部分,初始時,所有元素均視為未交換過。每次將第一個元素與未交換過的元素中的最後一個元素進行交換,再從第一個元素到剩下未交換過的元素中的最後一個進行建堆,直到只剩下第一個元素未交換。
時間複雜度(平均):O(n logn)
時間複雜度(最壞):O(n logn)
空間複雜度:O(1)
穩定性:不穩定
template<typename KeyType, typename InfoType>
void heapAdjust(HeapType<KeyType, InfoType>& H, int s, int m)//調整堆
{//在s到m範圍裡調整s到合適的位置
RedType<KeyType, InfoType> R = H.data[s];
int j;
for (j = 2 * s; j <= m; j *= 2)//尋找s的後代,直到s比兩個兒子都大
{
if (j < m && H.data[j].key < H.data[j + 1].key)//尋找s的左右兒子中大的那個,j必須小於m,否則j+1=m+1可能影響結果
j++;
if (H.data[j].key <= R.key)//必須用R,不能用s,因為s可能已經與j交換過,此時s其實是存的是交換的j的值
break;
H.data[s] = H.data[j];
s = j;
}
H.data[s] = R;
}
template<typename KeyType,typename InfoType>
void heapSort(HeapType<KeyType, InfoType>& H)//堆排序
{
for (int i = H.length / 2; i > 0; i--)//建堆
heapAdjust(H, i, H.length);
for (int i = H.length; i > 1; i--)//交換第一個和最後一個元素,然後重新調整堆
{
RedType<KeyType, InfoType>R = H.data[1];
H.data[1] = H.data[i];
H.data[i] = R;
heapAdjust(H, 1, i - 1);
}
}
基數排序
從低位到高位,對元素的關鍵字的每一位進行分配和收集。首先進行分配,根據位將每一個元素加入到對應位的靜態連結串列中。然後進行收集,從小到大按每一個靜態連結串列的順序將元素連結起來。進行完一輪分配和收集之後繼續對關鍵字的下一位進行分配和收集,直至每一位都分配收集完成。
時間複雜度(平均):O(d(n+rd))/O(dn)
時間複雜度(最壞):O(d(n+rd))/O(dn)
空間複雜度:O(rd)
穩定性:穩定
template<typename KeysType>
KeysType ord(KeysType K, int i)//計算第i位的值
{
KeysType t;
while (i--)
{
t = K;
t %= 10;
K /= 10;
}
return t;
}
template<typename KeysType, typename InfoType>
void distribute(SLCell<KeysType, InfoType>*& r, int i, ArrType& first, ArrType& end)
{
for (int j = 0; j < RADIX; j++)//初始化
first[j] = 0;
for (int p = r[0].next; p > 0; p = r[p].next)
{
int j = ord(r[p].keys[0], i);
if (first[j] == 0)//還沒有元素
first[j] = p;//作為第一個元素
else//已經有元素
r[end[j]].next = p;//作為下一個元素
end[j] = p;//最後一個元素
}
}
template<typename KeysType, typename InfoType>
void collect(SLCell<KeysType, InfoType>*& r, int i, ArrType first, ArrType end)
{
int j;
for (j = 0; first[j] == 0; j++);//跳過無元素的部分
r[0].next = first[j];//設定第一個元素
int e = end[j];//最後一個元素的下標
while (j < RADIX - 1)
{
for (j++; j < RADIX - 1 && first[j] == 0; j++);//跳過無元素的部分
if (first[j] != 0)//因為找到有元素的部分而退出迴圈
{
r[e].next = first[j];
e = end[j];
}
}
r[e].next = 0;
}
template<typename KeysType, typename InfoType>
void radixSort(SLList<KeysType, InfoType>& L)//基數排序
{
ArrType first, end;
for (int i = 1; i <= L.keynum; i++)//對每一位進行分配和收集
{
distribute(L.r, i, first, end);
collect(L.r, i, first, end);
}
}
測試
int randint(int start, int end)
{
return rand() % (end - start) + start;
}
int main()
{
srand((unsigned int)time(0));
SqList<RedType<int, string>> L1, L2, L3, L4, L5;
initSqList(L1);
initSqList(L2);
initSqList(L3);
initSqList(L4);
initSqList(L5);
SLList<int, string> L6;
for (int i = 1; i < randint(10, 15); i++)
{
RedType<int, string> t;
t.key = randint(1, 1000);
insertSqList(L1, t, i);
insertSqList(L2, t, i);
insertSqList(L3, t, i);
insertSqList(L4, t, i);
insertSqList(L5, t, i);
}
int* data = new int[L1.length];
for (int i = 0; i < L1.length; i++)
data[i] = L1.data[i + 1].key;
initSLList(L6, data, L1.length, 3);
cout << "L1 = ";
for (int i = 1; i <= L1.length; i++)
cout << L1.data[i].key << " ";
cout << endl;
cout << "L2 = ";
for (int i = 1; i <= L2.length; i++)
cout << L2.data[i].key << " ";
cout << endl;
cout << "L3 = ";
for (int i = 1; i <= L3.length; i++)
cout << L3.data[i].key << " ";
cout << endl;
cout << "L4 = ";
for (int i = 1; i <= L4.length; i++)
cout << L4.data[i].key << " ";
cout << endl;
cout << "L5 = ";
for (int i = 1; i <= L5.length; i++)
cout << L5.data[i].key << " ";
cout << endl;
cout << "L6 = ";
for (int i = 1; i <= L6.recnum; i++)
cout << L6.r[i].keys[0] << " ";
cout << endl;
cout << "L1 after insertSort = ";
insertSort(L1);
for (int i = 1; i <= L1.length; i++)
cout << L1.data[i].key << " ";
cout << endl;
cout << "L2 after bubbleSort = ";
bubbleSort(L2);
for (int i = 1; i <= L2.length; i++)
cout << L2.data[i].key << " ";
cout << endl;
cout << "L3 after selectSort = ";
selectSort(L3);
for (int i = 1; i <= L3.length; i++)
cout << L3.data[i].key << " ";
cout << endl;
cout << "L4 after quickSort = ";
quickSort(L4);
for (int i = 1; i <= L4.length; i++)
cout << L4.data[i].key << " ";
cout << endl;
cout << "L5 after heapSort = ";
heapSort(L5);
for (int i = 1; i <= L5.length; i++)
cout << L5.data[i].key << " ";
cout << endl;
cout << "L6 after radixSort = ";
radixSort(L6);
for (int i = L6.r[0].next; i > 0; i = L6.r[i].next)
cout << L6.r[i].keys[0] << " ";
cout << endl;
system("pause");
return 0;
}