大话数据结构 :排序
排序算法概要
冒泡排序和快速排序
快速排序是冒泡排序的升級,冒泡排序的算法性能較低時間性能O(n2),而快速排序平均可以達(dá)到o(nlogn)。冒泡排序就是兩兩比較,直到所有的位置都是有序排列的數(shù)據(jù)。而快速排序就是在兩兩比較的過程中增加了一個將比當(dāng)前數(shù)據(jù)小的都放在一段,比當(dāng)前數(shù)據(jù)大的都放在另一端的思想,提高了算法效率。
代碼
#include <stdio.h> #include <string.h> #include <ctype.h> #include <stdlib.h> #include <io.h> #include <math.h> #include <time.h>#define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0#define MAX_LENGTH_INSERT_SORT 7 /* 用于快速排序時判斷是否選用插入排序闕值 */typedef int Status;#define MAXIZE 10000 /* 用于要排序數(shù)組個數(shù)最大值,可根據(jù)需要修改 */ typedef struct {int r[MAXIZE + 1];int length; }SqList;/* 交換L中數(shù)組r的下標(biāo)為i和j的值 */ void swap(SqList* L, int i, int j) {int temp = L->r[i];L->r[i] = L->r[j];L->r[j] = temp; }void print(SqList L) {int i;for (int i = 1; i < L.length; i++)printf("%d,", L.r[i]);printf("\n"); }/* 對順序表L作交換排序(冒泡排序初級版) */ void BubbleSort0(SqList* L) {int i;int j;for (int i = 1; i < L->length; i++){for (int j = i + 1; j <= L->length; j++){if (L->r[i] > L->r[j]){swap(L, i, j);/* 交換L->r[i]與L->r[j]的值 */}}} }/* 對順序表L作冒泡排序 */ void BubbleSort(SqList* L) {int i;int j;for (int i = 1; i < L->length; i++){for (int j = L->length - 1; j >= i; j--){if (L->r[j] > L->r[j + 1]) //冒泡排序經(jīng)典方法{swap(L, j, j + 1);}}} }/* 對順序表L作改進(jìn)冒泡算法*/ void BubbleSort2(SqList* L) {int i;int j;Status flag = TRUE;for (int i = 1; i < L->length && flag; i++){flag = FALSE;for (int j = (*L).length - 1; j >= i; j--){if (L->r[j] > L->r[j + 1]){swap(L, j, j+1);flag = TRUE;}}} }/**************** 快速排序******************************** */ /* 交換順序表L中子表的記錄,使樞軸記錄到位,并返回其所在位置 */ /* 此時在它之前(后)的記錄均不大(小)于它。 */int Partition(SqList* L, int low, int high) {int pivotkey;pivotkey = L->r[low]; /* 令第一個元素為樞軸*/while (low < high)/* 從表的兩端交替地向中間掃描 */{while ((low < high) && (L->r[high] >= pivotkey)){high--;}swap(L, low, high);/* 將比樞軸記錄小的記錄交換到低端 */while (low < high && L->r[low] <= pivotkey){low++;}swap(L, low, high);}return low; /* 返回樞軸所在位置 */ }/* 對順序表中的子序列作快速排序*/ void QSort(SqList* L, int low, int high) {int pivot;if(low < high){pivot = Partition(L, low, high); /* 將L->r[low..high]一分為二,算出樞軸值pivot */QSort(L, low, pivot - 1); /* 對低子表遞歸排序 */QSort(L, pivot + 1, high); /* 對高子表遞歸排序 */} } /* 對順序表L作快速排序 */ void QuickSort(SqList* L) {QSort(L, 1, L->length); }/* 改進(jìn)后快速排序******************************** */ /* 快速排序優(yōu)化算法 */ int Partition1(SqList* L, int low, int high) {int pivotkey;int m = low + (high - low) / 2; //三數(shù)確定P值所在位置if (L->r[low] > L->r[high])swap(L, low, high); /* 交換左端與右端數(shù)據(jù),保證左端較小 */if (L->r[m] > L->r[high])swap(L, high, m); /* 交換中間與右端數(shù)據(jù),保證中間較小 */if (L->r[m] > L->r[low])swap(L, m, low); /* 交換中間與左端數(shù)據(jù),保證左端較小 */pivotkey = L->r[low]; /* 用子表的第一個記錄作樞軸記錄 */L->r[0] = pivotkey; /* 將樞軸關(guān)鍵字備份到L->r[0] */while (low < high) /* 從表的兩端交替地向中間掃描 */{while (low < high && L->r[high] >= pivotkey)high--;L->r[low] = L->r[high];while (low < high && L->r[low] <= pivotkey)low++;L->r[high] = L->r[low];}L->r[low] = L->r[0];return low; /* 返回樞軸所在位置 */}/* 對順序表L作直接插入排序 */ void InsertSort(SqList* L) {int i, j;for (i = 2; i <= L->length; i++){if (L->r[i] < L->r[i - 1]) /* 需將L->r[i]插入有序子表 */{L->r[0] = L->r[i]; /* 設(shè)置哨兵 */for (j = i - 1; L->r[j] > L->r[0]; j--)L->r[j + 1] = L->r[j]; /* 記錄后移 */L->r[j + 1] = L->r[0]; /* 插入到正確位置 */}} }void QSort1(SqList* L, int low, int high) {int pivot;if ((high - low) > MAX_LENGTH_INSERT_SORT){while (low < high){pivot = Partition1(L, low, high); /* 將L->r[low..high]一分為二,算出樞軸值pivot */QSort1(L, low, pivot - 1); /* 對低子表遞歸排序 *//* QSort(L,pivot+1,high); /* 對高子表遞歸排序 */low = pivot + 1; /* 尾遞歸 */}}elseInsertSort(L); }/* 對順序表L作快速排序 */ void QuickSort1(SqList* L) {QSort1(L, 1, L->length); } #define N 9 int main() {int i;/* int d[N]={9,1,5,8,3,7,4,6,2}; */int d[N] = { 50,10,90,30,70,40,80,60,20 };/* int d[N]={9,8,7,6,5,4,3,2,1}; */SqList l0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10;for (i = 0; i < N; i++)l0.r[i + 1] = d[i];l0.length = N;l1 = l2 = l3 = l4 = l5 = l6 = l7 = l8 = l9 = l10 = l0;printf("排序前:\n");print(l0);printf("初級冒泡排序:\n");BubbleSort0(&l0);print(l0);printf("冒泡排序:\n");BubbleSort(&l1);print(l1);printf("改進(jìn)冒泡排序:\n");BubbleSort2(&l2);print(l2);printf("快速排序:\n");QuickSort(&l9);print(l9); }直接插入和希爾排序
直接插入算法簡單,就是從第2個元素開始,將其與首個元素比較,如果小于首個元素則將其插入到第一位,如果大于則比較之后的元素,直到達(dá)到自身。希爾排序是其改進(jìn),其采用首先保證一定間隔的元素是有序排列的,比如任意間隔為3的元素序列都是有序的,這一步采取的方法同直接插入,然后逐步將間隔縮小直到1,這是所有序列都有序。這個算法適合大部分?jǐn)?shù)據(jù)是有序的,主要優(yōu)點(diǎn)在于數(shù)據(jù)的移動較小。
代碼
/* 對順序表L作直接插入排序 */ void InsertSort(SqList* L) {int i, j;for (i = 2; i <= L->length; i++){if (L->r[i] < L->r[i - 1]) /* 需將L->r[i]插入有序子表 */{L->r[0] = L->r[i]; /* 設(shè)置哨兵 */for (j = i - 1; L->r[j] > L->r[0]; j--)L->r[j + 1] = L->r[j]; /* 記錄后移 */L->r[j + 1] = L->r[0]; /* 插入到正確位置 */}} }/* 對順序表L作希爾排序 */ void ShellSort(SqList* L) {int i;int j;int k = 1;int increment = L->length;do{increment = increment / 3 + 1;/* 增量序列 */for (int i = increment + 1; i <= L->length; i++){if (L->r[i] < L->r[i - increment])/* 需將L->r[i]插入有序增量子表 */{L->r[0] = L->r[i]; /* 暫存在L->r[0] */for (j = i - increment; j > 0 && L->r[0] < L->r[j]; j -= increment)L->r[j + increment] = L->r[j]; /* 記錄后移,查找插入位置 */L->r[j + increment] = L->r[0]; /* 插入 */}}printf(" 第%d趟排序結(jié)果: ", ++k);print(*L);} while (increment > 1); }簡單選擇排序和堆排序
簡單選擇排序就是首先找到最小的,然后找到第2小的,依次排序。堆排序是把數(shù)據(jù)按照完全二叉樹結(jié)構(gòu)組織起來,構(gòu)成一個大頂堆或者小頂堆。然后每次從堆頂取出一個數(shù),接著將最后一位數(shù)移到堆頂,重新堆數(shù)據(jù)按照大頂堆排序,此時操作實(shí)際比較簡單。
具體看代碼,主要就是大頂堆初始排序要從底層開始,之后再排序就容易了。
代碼
/* 對順序表L作簡單選擇排序 */ void SelectSort(SqList* L) {int i, j, min;for (i = 1; i < L->length; i++){min = i; /* 將當(dāng)前下標(biāo)定義為最小值下標(biāo) */for (j = i + 1; j <= L->length; j++)/* 循環(huán)之后的數(shù)據(jù) */{if (L->r[min] > L->r[j]) /* 如果有小于當(dāng)前最小值的關(guān)鍵字 */min = j; /* 將此關(guān)鍵字的下標(biāo)賦值給min */}if (i != min) /* 若min不等于i,說明找到最小值,交換 */swap(L, i, min); /* 交換L->r[i]與L->r[min]的值 */} }/* 堆排序********************************** */ /* 已知L->r[s..m]中記錄的關(guān)鍵字除L->r[s]之外均滿足堆的定義, */ /* 本函數(shù)調(diào)整L->r[s]的關(guān)鍵字,使L->r[s..m]成為一個大頂堆 */ void HeapAdjust(SqList* L, int s, int m) {int temp;temp = L->r[s];for (int j = 2 * s; j <= m; j *= 2){if (j < m && L->r[j] < L->r[j + 1]){++j;/* j為關(guān)鍵字中較大的記錄的下標(biāo) */}if (temp >= L->r[j])break;L->r[s] = L->r[j];s = j;}L->r[s] = temp;/* 插入 */ }/* 對順序表L進(jìn)行堆排序 */ void HeapSort(SqList *L) {for (int i = L->length / 2; i > 0; i--)//注意這里的i值表示從底層開始大頂堆{HeapAdjust(L, i, L->length);}for (int i = L->length; i > 1; i--){swap(L, 1, i);HeapAdjust(L, 1, i - 1); /* 將L->r[1..i-1]重新調(diào)整為大根堆 */} }歸并排序
歸并排序可以說是排序算法中效率,穩(wěn)定性方面最好的,實(shí)現(xiàn)也比較簡單。主要就是將數(shù)據(jù)分片,片內(nèi)排序然后合并,對于歸并排序應(yīng)該使用它的分遞歸方式,占用內(nèi)存少。
代碼
/**************** 歸并排序********************************** */ /* 將有序的SR[i..m]和SR[m+1..n]歸并為有序的TR[i..n] */ void Merge(int SR[], int TR[], int i, int m, int n) {int k,j;for (j = m + 1, k = i; i <= m && j <= n; k++)/* 將SR中記錄由小到大地并入TR */{if (SR[i] < SR[j])TR[k] = SR[i++]; //注意這里的i++elseTR[k] = SR[j++];}if (i <= m){for (int h = 0; h <= m - i; h++)TR[k + h] = SR[i + h]; /* 將剩余的SR[i..m]復(fù)制到TR */}if (j <= n){for (int h = 0; h <= h - j; h++)TR[h + k] = SR[j + h]; /* 將剩余的SR[j..n]復(fù)制到TR */} }/* 遞歸法 */ /* 將SR[s..t]歸并排序?yàn)門R1[s..t] */ void MSort(int SR[], int TR1[], int s, int t) {int m;int TR2[MAXIZE + 1];if (s == t)TR1[s] = SR[s];else{m = (s + t) / 2; /* 將SR[s..t]平分為SR[s..m]和SR[m+1..t] */MSort(SR, TR2, s, m); /* 遞歸地將SR[s..m]歸并為有序的TR2[s..m] */MSort(SR, TR2, m + 1, t); /* 遞歸地將SR[m+1..t]歸并為有序的TR2[m+1..t] */Merge(TR2, TR1, s, m, t); /* 將TR2[s..m]和TR2[m+1..t]歸并到TR1[s..t] */} }/* 對順序表L作歸并排序 */ void MergeSort(SqList* L) {MSort(L->r, L->r, 1, L->length); } /* 非遞歸法 */ /* 將SR[]中相鄰長度為s的子序列兩兩歸并到TR[] */ void MergePass(int SR[], int TR[], int s, int n) {int i = 1;int j;while (i <= n - 2 * s + 1){/* 兩兩歸并 */Merge(SR, TR, i, i + s - 1, i + 2 * s - 1);i = i + 2 * s;}if (i < n - s + 1) /* 歸并最后兩個序列 */Merge(SR, TR, i, i + s - 1, n);else /* 若最后只剩下單個子序列,已經(jīng)排好序 */for (j = i; j <= n; j++)TR[j] = SR[j]; } /* 對順序表L作歸并非遞歸排序 */ void MergeSort2(SqList* L) {int* TR = (int*)malloc(L->length * sizeof(int));/* 申請額外空間 */int k = 1;while (k < L->length){MergePass(L->r, TR, k, L->length);k = 2 * k;/* 子序列長度加倍 */MergePass(TR, L->r, k, L->length);k = 2 * k;/* 子序列長度加倍 */} }總結(jié)
以上是生活随笔為你收集整理的大话数据结构 :排序的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大话数据结构:散列表
- 下一篇: leetcode刷题集:栈与队列