昨天學習了一下七大排序中的兩個——冒泡排序和快速排序,遂用Lua簡單的實現了一下。
冒泡排序:
--[[-- - orderByBubbling: 冒泡排序 - @param: t, - @return: list - table ]] function table.orderByBubbling(t) for i = 1, #t do for j = #t, i + 1, -1 do if t[j - 1] > t[j] then swap(t, j, j - 1) printT(t) end end end return t end
快速排序:
1 --[[-- 2 - partition: 獲得快排中介值位置 3 - @param: list, low, high - 參數描述 4 - @return: pivotKeyIndex - 中介值索引 5 ]] 6 function partition(list, low, high) 7 local low = low 8 local high = high 9 local pivotKey = list[low] -- 定義一個中介值 10 11 -- 下面將中介值移動到列表的中間 12 -- 當左索引與右索引相鄰時停止循環 13 while low < high do 14 -- 假如當前右值大於等於中介值則右索引左移 15 -- 否則交換中介值和右值位置 16 while low < high and list[high] >= pivotKey do 17 high = high - 1 18 end 19 swap(list, low, high) 20 21 -- 假如當前左值小於等於中介值則左索引右移 22 -- 否則交換中介值和左值位置 23 while low < high and list[low] <= pivotKey do 24 low = low + 1 25 end 26 swap(list, low, high) 27 end 28 return low 29 end 30 31 --[[-- 32 - orderByQuick: 快速排序 33 - @param: list, low, high - 參數描述 34 - @return: list - table 35 ]] 36 function orderByQuick(list, low, high) 37 if low < high then 38 -- 返回列表中中介值所在的位置,該位置左邊的值都小於等於中介值,右邊的值都大於等於中介值 39 local pivotKeyIndex = partition(list, low, high) 40 -- 分別將中介值左右兩邊的列表遞歸快排 41 orderByQuick(list, low, pivotKeyIndex - 1) 42 orderByQuick(list, pivotKeyIndex + 1, high) 43 end 44 end
效果測試:
1 local printT = function(t) 2 print("printT ---------------") 3 table.walk(t, function(v, k) 4 print(k, v) 5 end) 6 print("---------------") 7 end 8 9 local t = {5,2,5,4,-100,25,76,-10,-100,46,5,2,5,4,-100,25,76,-10,-100,46,5,2,5,4,-100,25,76,-10,-100,46,5,2,5,4,-100,25,76,-10,-100,46,5,2,5,4,-100,25,76,-10,-100,46,5,2,5,4,-100,25,76,-10,-100,46,5,2,5,4,-100,25,76,-10,-100,46,5,2,5,4,-100,25,76,-10,-100,46} 10 -- local t = {5,2,5,4} 11 local num = table.nums(t) 12 orderByQuick(t, 1, num) -- 總結,快拍bushi 13 -- table.orderByBubbling(t) 14 print("after order--------") 15 printT(t)
結果當然是兩種排序算法都正確的排出了table中的順序,但是效率有了明顯的差異,
這是冒泡排序所用時間:,然后是快速排序所用時間:
,原來算法的好壞表現出來的可以差這么多啊。。。
下面是我學習這兩個算法的帖子:
http://www.cnblogs.com/mcgrady/p/3226740.html,感謝原作者的分享。。。
排序是我們生活中經常會面對的問題。同學們做操時會按照從矮到高排列;老師查看上課出勤情況時,會按學生學號順序點名;高考錄取時,會按成績總分降序依次錄取等。排序是數據處理中經常使用的一種重要的運算,它在我們的程序開發中承擔着非常重要的角色。
排序分為以下四類共七種排序方法:
交換排序:
1) 冒泡排序
2) 快速排序
選擇排序:
3) 直接選擇排序
4) 堆排序
插入排序:
5) 直接插入排序
6) 希爾排序
合並排序:
7) 合並排序
這一篇文章主要總結的是交換排序,即冒泡排序和C#提供的快速排序。交換排序的基本思想是:兩兩比較待排序記錄的關鍵字,如果發現兩個記錄的次序相反時即進行交換,直到所有記錄都沒有反序時為目上。本篇文章主要從以下幾個方面進行總結:
1,冒泡排序及算法實現
2,快速排序及算法實現
3,冒泡排序VS快速排序
1,冒泡排序及算法實現
什么時冒泡排序呢?冒泡排序是一種簡單的排序方法,其基本思想是:通過相鄰元素之間的比較和交換,使關鍵字較小的元素逐漸從底部移向頂部,就像水底下的氣泡一樣逐漸向上冒泡,所以使用該方法的排序稱為“冒泡”排序。
下面以一張圖來展示冒泡排序的全過程,其中方括號內為下一躺要排序的區間,方括號前面的一個關鍵字為本躺排序浮出來的最小關鍵字。
了解了冒泡排序的實現過程后,我們很容易寫出冒泡排序的算法實現。
C#版:
namespace BubbleSort.CSharp { class Program { static void Main(string[] args) { List<int> list = new List<int>() { 50, 10, 90, 30, 70, 40, 80, 60, 20 }; Console.WriteLine("********************冒泡排序********************"); Console.WriteLine("排序前:"); Display(list); Console.WriteLine("排序后:"); BubbleSort(list); Display(list); Console.ReadKey(); } /// <summary> /// 打印結果 /// </summary> /// <param name="list"></param> private static void Display(List<int> list) { Console.WriteLine("\n**********展示結果**********\n"); if (list!=null&&list.Count>0) { foreach (var item in list) { Console.Write("{0} ", item); } } Console.WriteLine("\n**********展示完畢**********\n"); } /// <summary> /// 冒泡排序算法 /// </summary> /// <param name="list"></param> /// <returns></returns> private static List<int> BubbleSort(List<int> list) { int temp; //做多少躺排序(最多做n-1躺排序) for (int i = 0; i < list.Count-1; i++) { //從后往前循環比較(注意j的范圍) for (int j = list.Count - 1; j > i; j--) { if (list[j - 1] > list[j]) { //交換次序 temp=list[j-1]; list[j-1]=list[j]; list[j] = temp; } } } return list; } } }
程序運行結果:
C語言版:
/*包含頭文件*/ #include "stdio.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 /* 用於要排序數組個數最大值,可根據需要修改 */ #define MAXSIZE 100 typedef int Status; typedef struct { int data[MAXSIZE]; int length; }SeqList; /*冒泡排序算法*/ void BubbleSort(SeqList *seqList) { int i,j; //做多少躺排序(最多做n-1躺排序) for (i=0;i<seqList->length-1;i++) { //從后往前循環比較(注意j的范圍) for (j=seqList->length-1;j>i;j--) { if (seqList->data[j-1]>seqList->data[j]) { //交換次序 int temp=seqList->data[j-1]; seqList->data[j-1]=seqList->data[j]; seqList->data[j]=temp; } } } } /*打印結果*/ void Display(SeqList *seqList) { int i; printf("\n**********展示結果**********\n"); for (i=0;i<seqList->length;i++) { printf("%d ",seqList->data[i]); } printf("\n**********展示完畢**********\n"); } #define N 9 void main() { int i,j; SeqList seqList; //定義數組 int d[N]={50,10,90,30,70,40,80,60,20}; for (i=0;i<N;i++) { seqList.data[i]=d[i]; } seqList.length=N; printf("***************冒泡排序***************\n"); printf("排序前:"); Display(&seqList); BubbleSort(&seqList); printf("\n排序后:"); Display(&seqList); getchar(); }
程序運行結果同C#版
2,快速排序及算法實現
快速排序(Quick Sort)又稱為划分交換排序。快速排序是對冒泡排序的一種改進方法,在冒泡排序中,進行記錄關鍵字的比較和交換是在相鄰記錄之間進行的,記錄每次交換只能上移或下移一個相鄰位置,因而總的比較和移動次數較多,效率相對較低。而在快速排序中,記錄關鍵字的比較和記錄的交換是從兩端向中間進行的,待排序關鍵字較大的記錄一次就能夠交換到后面單元中,而關鍵字較小的記錄一次就能交換到前面單元中,記錄每次移動的距離較遠,因此總的比較和移動次數較少,速度較快,故稱為“快速排序”。
快速排序的基本思想是:通過一躺排序將待排記錄分割成獨立的兩部分, 其中一部分記錄的關鍵字均比另一部分記錄的關鍵字小,則可分別對這兩部分記錄繼續進行排序,以達到整個序列有序的目的。
下面是實現代碼:
C#版:
namespace QuickSort.CSharp { class Program { static void Main(string[] args) { List<int> list = new List<int> { 50, 10, 90, 30, 70, 40, 80, 60, 20 }; Console.WriteLine("********************快速排序********************"); Console.WriteLine("排序前:"); Display(list); Console.WriteLine("排序后:"); QuickSort(list,0,list.Count-1); Display(list); Console.ReadKey(); } /// <summary> /// 打印列表元素 /// </summary> /// <param name="list"></param> private static void Display(List<int> list) { Console.WriteLine("\n**********展示結果**********\n"); if (list != null && list.Count > 0) { foreach (var item in list) { Console.Write("{0} ", item); } } Console.WriteLine("\n**********展示完畢**********\n"); } /// <summary> /// 快速排序算法 /// </summary> /// <param name="list"></param> /// <param name="low"></param> /// <param name="high"></param> public static void QuickSort(List<int> list, int low, int high) { if (low < high) { //分割數組,找到樞軸 int pivot = Partition(list,low,high); //遞歸調用,對低子表進行排序 QuickSort(list,low,pivot-1); //對高子表進行排序 QuickSort(list,pivot+1,high); } } /// <summary> /// 分割列表,找到樞軸 /// </summary> /// <param name="list"></param> /// <param name="low"></param> /// <param name="high"></param> /// <returns></returns> private static int Partition(List<int> list, int low, int high) { //用列表的第一個記錄作樞軸記錄 int pivotKey = list[low]; while (low < high) { while (low < high && list[high] >= pivotKey) high--; Swap(list,low,high);//交換 while (low < high && list[low] <= pivotKey) low++; Swap(list,low,high); } //返回樞軸所在位置 return low; } /// <summary> /// 交換列表中兩個位置的元素 /// </summary> /// <param name="list"></param> /// <param name="low"></param> /// <param name="high"></param> /// <returns></returns> private static void Swap(List<int> list, int low, int high) { int temp = -1; if (list != null && list.Count > 0) { temp = list[low]; list[low] = list[high]; list[high] = temp; } } } }
程序運行結果:
C語言版:
/*包含頭文件*/ #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 /* 用於要排序數組個數最大值,可根據需要修改 */ #define MAXSIZE 100 typedef int Status; typedef struct { int data[MAXSIZE]; int length; }SeqList; /*快速排序算法*/ void QuickSort(SeqList *seqList,int low,int high) { int pivot; while(low<high) { //分割列表,找到樞軸 pivot=Partition(seqList,low,high); //遞歸調用,對低子列表進行排序 QuickSort(seqList,low,pivot-1); QuickSort(seqList,pivot+1,high); } } /*交換順序表L中子表的記錄,使樞軸記錄到位,並返回其所在位置*/ /* 此時在它之前(后)的記錄均不大(小)於它。 */ int Partition(SeqList *seqList,int low,int high) { int pivotkey; pivotkey=seqList->data[low]; /* 從表的兩端交替地向中間掃描 */ while(low<high) { while(low<high&&seqList->data[high]>=pivotkey) high--; Swap(seqList,low,high); while(low<high&&seqList->data[low]<=pivotkey) low++; Swap(seqList,low,high); } return low; } /* 交換L中數組SeqList下標為i和j的值 */ void Swap(SeqList *seqList,int i,int j) { int temp; temp=seqList->data[i]; seqList->data[i]=seqList->data[j]; seqList->data[j]=temp; } /*打印結果*/ void Display(SeqList *seqList) { int i; printf("\n**********展示結果**********\n"); for (i=0;i<seqList->length;i++) { printf("%d ",seqList->data[i]); } printf("\n**********展示完畢**********\n"); } #define N 9 void main() { int i,j; SeqList seqList; //定義數組 int d[N]={50,10,90,30,70,40,80,60,20}; for (i=0;i<N;i++) { seqList.data[i]=d[i]; } seqList.length=N; printf("***************快速排序***************\n"); printf("排序前:"); Display(&seqList); QuickSort(&seqList,0,seqList.length-1); printf("\n排序后:"); Display(&seqList); getchar(); }
程序運行結果同上。
3,冒泡排序VS快速排序
關於冒泡排序和快速排序之間排序速度的比較我就選用C#語言版本的來進行,代碼如下:
static void Main(string[] args) { //共進行三次比較 for (int i = 1; i <= 3; i++) { //初始化List List<int> list = new List<int>(); for (int j = 0; j < 1000; j++) { Thread.Sleep(1); list.Add(new Random((int)DateTime.Now.Ticks).Next(0,10000)); } //快速排序(系統內置)耗費時間 Console.WriteLine("\n第"+i+"次比較:"); Stopwatch watch = new Stopwatch(); watch.Start(); var result = list.OrderBy(p => p).ToList(); watch.Stop(); Console.WriteLine("\n快速排序(系統)耗費時間:"+watch.ElapsedMilliseconds); Console.WriteLine("輸出前十個數:"+String.Join(",",result.Take(10).ToList())); //快速排序(自定義)耗費時間 watch.Start(); QuickSort.CSharp.Program.QuickSort(list,0,list.Count-1); watch.Stop(); Console.WriteLine("\n快速排序(自定義)耗費時間:" + watch.ElapsedMilliseconds); Console.WriteLine("輸出前十個數:" + String.Join(",", result.Take(10).ToList())); //冒泡排序耗費時間 watch.Start(); result = BubbleSort(list); watch.Stop(); Console.WriteLine("\n冒泡排序耗費時間:" + watch.ElapsedMilliseconds); Console.WriteLine("輸出前十個數:" + String.Join(",", result.Take(10).ToList())); } Console.ReadKey(); }
比較結果如圖:
可見,快速排序的速度比冒泡排序要快。