准备工作
是参考这里,根据自己理解写的lua版,若有问题或者更好方案,可以留言讨论哦!
时间复杂度从小到大: 冒泡(O(n2))–>选择(O(n2))–>插入(O(n2))–>快速(O(nlogn))–>希尔(分段,O(n1.5))–>堆排序(O(n))
- 打印表数
-- 打印表数据
local function printTable(arg)
if arg == nil then
print("输入表为空")
return
end
if type(arg) ~= "table" then
print(arg)
return
end
local t = "{"
for k, v in pairs(arg) do
t = t .. v .. ","
end
print(t .. "}")
end
- 数组数据交换
-- 数组i,j位置交换数据
local function Swap(tab,i,j,isPrint)
local length = #tab
if i == j or i < 1 or j < 1 or j > length or i > length then
return
end
local temp = tab[i]
tab[i] = tab[j]
tab[j] = temp
if isPrint ~= nil then
printTable(arr)
end
end
- 准备数据
-- 准备相同的数组
local arr0 = {2,5,3,6,7,1,4,8,0,9}
local arr1 = {2,5,3,6,7,1,4,8,0,9}
local arr2 = {2,5,3,6,7,1,4,8,0,9}
local arr3 = {2,5,3,6,7,1,4,8,0,9}
local arr4 = {2,5,3,6,7,1,4,8,0,9}
local arr5 = {2,5,3,6,7,1,4,8,0,9}
- table数据翻转(补充)
下了实现的排序方法默认是升序的,为了降序加了参数isDes,可以利用这个翻转函数,但是为了练手自己又写了降序的方法,自行参考
-- table数据翻转
function ReverseTable(tab)
local length = #tab
if length < 1 then
return
end
local start = 1
while start < length do
Swap(tab,start,length)
start = start + 1
length = length - 1
end
end
冒泡排序
- 思路
两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止 - 排序方法
-- 冒泡排序: isDes是否为降序
function BubbleSort(tab,isDes)
if tab == null or type(tab) ~= "table" then
return
end
local length = #tab
if length < 1 then
return
end
if isDes then
for i = length, 1 , -1 do
for j = i+1,length do
if tab[j - 1] < tab[j] then
Swap(tab,j-1,j)
end
end
end
return
end
for i = 1, length do
for j = length,i +1, -1 do
if tab[j - 1] > tab[j] then
Swap(tab,j-1,j)
end
end
end
end
- 优化排序
-- 冒泡排序: isDes是否为降序,优化版
function BubbleSortOpt(tab,isDes)
if arr == null or type(tab) ~= "table" then
return
end
local length = #tab
if length < 1 then
return
end
local flag = true
if isDes then
for i = length, 1, -1 do
if not flag then
break
end
flag = false
for j = 1,i-1 do
if tab[j ] < tab[j+1] then
Swap(tab,j,j + 1)
flag = true
end
end
end
return
end
for i = 1, length do
if not flag then
break
end
flag = false
for j = length,i +1, -1 do
k = k+1
if tab[j - 1] > tab[j] then
Swap(tab,j-1,j)
flag = true
end
end
end
end
- 排序测试
printTable(arr0)
-- 升序
BubbleSort(arr0)
printTable(arr0)
BubbleSortOpt(arr1)
printTable(arr1)
-- 降序
BubbleSort(arr2,true)
printTable(arr2)
BubbleSortOpt(arr3,true)
printTable(arr3)
- 优化说明
添加一个标识flag,当再一次遍历已经是有序的时候(无需再交换数据),就可以停止了遍历了
选择排序
- 思路
每次从在n-i+1(i=1,2,…,n-1) 个数据中找到最小(或最大)的数据,与i位置数据进行交换 - 排序方法
-- 选择排序: isDes是否为降序
function SelectSort(tab,isDes)
if tab == null or type(tab) ~= "table" then
return
end
local length = #tab
if length < 1 then
return
end
if isDes then
for i = 1, length do
local max = i
for j = i+1,length do
if tab[max] < tab[j] then
max = j
end
end
if i ~= max then
Swap(tab,i,max)
end
end
return
end
for i = 1, length do
local min = i
for j = i+1,length do
if tab[min] > tab[j] then
min = j
end
end
if i ~= min then
Swap(tab,i,min)
end
end
end
- 优化排序
-- 选择排序: isDes是否为降序,优化版
function SelectSortOpt(tab,isDes)
if tab == nil or type(tab) ~= "table" then
return
end
local length = #tab
if length < 1 then
return
end
local temp,index,i = 1,1, 1
if isDes then
while i <= length do
if i < temp and tab[i] < tab[temp] then
Swap(tab,i, temp)
i = i + 1
end
index = i
for j = i + 1, length do
if tab[j] > tab[index] then
temp = index
index = j
elseif tab[j] > tab[temp] then
temp = j
end
end
if i ~= index then
Swap(tab, i, index)
end
i = i + 1
end
return
end
while i <= length do
if i < temp and tab[i] > tab[temp] then
Swap(tab,i,temp)
i = i + 1
end
index = i
for j = i +1 , length do
if tab[j] < tab[index] then
temp = index
index = j
elseif tab[j] < tab[temp] then
temp = j
end
end
if i ~= index then
Swap(tab,i,index)
end
i = i + 1
end
end
- 排序测试
printTable(arr0)
-- 升序
SelectSort(arr0)
printTable(arr0)
SelectSortOpt(arr1)
printTable(arr1)
-- 降序
SelectSort(arr2,true)
printTable(arr2)
SelectSortOpt(arr3,true)
printTable(arr3)
- 优化说明
一次循环中,在找到最小(或最大)值之前,min(或max)所标识的就是当前的最小(或最大)值,找到数组的最小(或最大)值后用temp先缓存当前的min(或max),在下次循环之前,temp所标记的就是剩余数值中最小(或最大)的值了,可以先进行一次交换,可省一次循环
插入排序
- 思路
将一个数据插入到已排好序的表中,从而得到一个新的、个数增1的有序表 - 排序方法
-- 插入排序: isDes是否为降序
function InsertSort(tab,isDes)
if tab == null or type(tab) ~= "table" then
return
end
local length = #tab
if length < 1 then
return
end
if isDes then
for i = 2, length do
if tab[i] > tab[i - 1] then
local j,temp = i-1,tab[i]
while j > 0 and tab[j] < temp do
tab[j+1]= tab[j]
j = j -1
end
tab[j+1] = temp
end
end
return
end
for i = 2, length do
if tab[i] < tab[i - 1] then
local j,temp = i-1,tab[i]
while j > 0 and tab[j] > temp do
tab[j+1]= tab[j]
j = j -1
end
tab[j+1] = temp
end
end
end
- 优化排序
插入排序算的优化是 希尔排序,后面会有 希尔排序 算法实现 - 排序测试
printTable(arr0)
-- 升序
InsertSort(arr0)
printTable(arr0)
-- 降序
InsertSort(arr1,true)
printTable(arr1)
希尔排序(插入排序升级版)
- 思路
- 基本有序:
小的关键字基本在前面,大的关键字基本在后面,不大不小的基本在中间。 - 跳跃分割策略:
将相距某个“增量”的记录组成一个子序列,这样才能保证在子序列内分别进行直接插入排序后得到的结果是基本有序而不是局部有序。
- 排序方法
-- 希尔排序: isDes是否为降序
function ShellSort(tab,isDes)
if tab == null or type(tab) ~= "table" then
return
end
local length = #tab
if length < 1 then
return
end
-- math.modf计算整数和小数部分,div为整数部分,dd为小数部分
local div,dd = math.modf(length)
if isDes then
repeat
div,dd = math.modf(div / 3+ 1)
--print(div,dd)
for i = div+1,length do
if tab[i] > tab[i - div] then
local j,temp = i-div,tab[i]
while j > 0 and tab[j] < temp do
tab[j+div]= tab[j]
j = j -div
end
tab[j+div] = temp
end
end
until div < 2
return
end
repeat
div,dd = math.modf(div / 3+ 1)
print(div,dd)
for i = div+1,length do
if tab[i] < tab[i - div] then
local j,temp = i - div,tab[i]
while j > 0 and tab[j] > temp do
tab[j+div] = tab[j]
j = j - div
end
tab[j+div] = temp
end
end
until div < 2
end
- 排序测试
printTable(arr0)
-- 升序
ShellSort(arr0)
printTable(arr0)
-- 降序
ShellSort(arr1,true)
printTable(arr1)
- 优化说明
- 希尔排序的关键并不是随便分组后各自排序,而是将相隔某个增量的数组组成一个子序列,实现跳跃式的移动。
- 增量的选择实验证明当增量序列为delt[k]=2^(t-k+1)-1( 0<=k<=t<=log2(n+1))时,效果较佳,但注意最后增量值必须等于1。
- 此时时间复杂度为O(n^1.5)
- 希尔排序因为是跳跃式记录,故不是一个稳定的排序算法。
快速排序
- 思路
通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键值均比另一部分记录的关键值小,则可以分别对这两部分记录继续进行排序,以达到整个序列有序的目的 - 排序方法
local function Partition(tab,startIndex,endIndex)
local pivotKey = tab[startIndex]
while startIndex < endIndex do
while startIndex < endIndex and tab[endIndex] >= pivotKey do
endIndex = endIndex -1
end
Swap(tab,startIndex, endIndex)
while startIndex < endIndex and tab[startIndex] <= pivotKey do
startIndex = startIndex + 1
end
Swap(tab,startIndex,endIndex)
end
return startIndex
end
local function GoToQuickSort(tab,startIndex,endIndex)
if type(tab) == "table" and startIndex <= endIndex then
_QuickSort(tab,startIndex,endIndex)
end
end
function _QuickSort(tab,startIndex,endIndex)
if startIndex == nil or type(startIndex) ~= "number" then
startIndex = 1
end
if endIndex == nil or type(endIndex) ~= "number" then
endIndex = length
end
if startIndex < endIndex then
local pivotkey = Partition(tab,startIndex, endIndex)
GoToQuickSort(tab,startIndex,pivotkey - 1)
GoToQuickSort(tab,pivotkey + 1,endIndex)
end
end
function QuickSort(tab,isDes)
if tab == nil or type(tab) ~= "table" then
return
end
local length = #tab
if length <= 1 then
return
end
_QuickSort(tab,1,length)
-- _QuickSort 实现升序,这里使用翻转实现降序
if isDes then
ReverseTable(tab)
end
end
- 排序测试
printTable(arr0)
QuickSort(arr0)
printTable(arr0)
QuickSort(arr1,true)
printTable(arr1)
- 优化说明
- 最优与平均时间复杂度O(nlogn)
- 最坏时间复杂度O(n^2)
- 空间复杂度O(logn)
- 快速排序是一种不稳定的排序方法