昨天學習了一下七大排序中的兩個——冒泡排序和快速排序,遂用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();
}
比較結果如圖:
可見,快速排序的速度比冒泡排序要快。





