最近用lua非常多,发现用lua写算法比cpp方便多了,就重新用lua写了一遍常用的排序算法,记录一下。
冒泡排序
最简短的排序算法
-- bubbleSort
-- 数组元素从头到尾前后两元素对比,更小(大)的数放前(后),重复数组长度-1次
-- 复杂度 0(n^2)
function bubbleSort(t)
for i=1, #t-1 do
for j=1, #t-1 do
if t[j] > t[j+1] then
t[j], t[j+1] = t[j+1], t[j]
end
end
end
end
ttt = {6,4,8,0,7,1,2,9,5,3}
print("before:")
print(table.concat(ttt,","))
bubbleSort(ttt)
print("after:")
print(table.concat(ttt,","))
插入排序
-- insertSort
-- 从头(尾)建立有序数组,遍历总数组从有序数组外取元素按大小插入有序数组中,直至遍历完总数组
-- 复杂度 0(n^2)
function insertSort(t)
for i=2, #t do
for j=1, i-1 do
local temp = t[i]
if temp < t[j] then -- 从已排序数组头开始遍历比较
for k=i, j,-1 do -- 有序数组插入位置后需向后投挪一位 给要插入的元素腾位置
t[k] = t[k-1]
end
t[j] = temp
end
end
end
end
function insertSort2(t) -- 效率更高
for i=2, #t do
print("=====i",i)
local temp = t[i]
--[[
for j=i-1, 1, -1 do
if temp < t[j] then -- way1 从已排序数组尾开始遍历比较 小于尾部元素则交换
t[j+1] = t[j]
t[j] = temp
end
end
]]
local j=i-1
while j>=1 do
-- way2 从已排序数组尾开始遍历比较 找出适合的位置,顺便往后扩展挪一位 最后插入适合的位置
if temp < t[j] then
t[j+1] = t[j]
j = j-1
else
break
end
end
t[j+1] = temp
end
end
ttt = {4,2,5,1,3}
print("before:")
print(table.concat(ttt,","))
-- insertSort(ttt)
insertSort2(ttt)
print("after:")
print(table.concat(ttt,","))
选择排序
-- selectSort
-- 遍历数组每次选择最小或最大的值替换到数组头或尾
-- 复杂度 0(n^2)
function selectSort(t)
for i=1, #t-1 do
local idx = i
for j=i+1, #t do
if t[idx] > t[j] then
idx = j
end
end
t[i], t[idx] = t[idx], t[i]
end
end
ttt = {6,4,8,0,7,1,2,9,5,3}
print("before:")
print(table.concat(ttt,","))
selectSort(ttt)
print("after:")
print(table.concat(ttt,","))
桶排序
-- bucketSort
-- 确定几个桶,将数组中的各个元素散列到各个桶中,后续桶要比前面桶的元素都大
-- 然后对桶中所有元素排序,最后按桶顺序,输出就是排序后的结果
-- 主要是根据数组中不同元素的大小 放入不同的桶中
-- 时间复杂度 O(n^2)
function printTable(t)
for i,v in pairs(t) do
print("i,v",i,v)
if type(v) == "table" then
printTable(v)
end
end
end
function selectSort(t)
for i=1, #t-1 do
local idx = i
for j=i+1, #t do
if t[idx] > t[j] then
idx = j
end
end
t[i], t[idx] = t[idx], t[i]
end
end
function bucketSort(t)
local maxNum = t[1]
local minNum = t[1]
-- 找出数组中最大和最小值
for i=1, #t do
maxNum = math.max(maxNum, t[i])
minNum = math.min(minNum, t[i])
end
-- 确定桶的数量
-- local bucketCnt = math.floor((maxNum-minNum)/#t) + 1
local bucketCnt = 2
-- 初始化桶
local bucketAttr = {}
for i=1, bucketCnt do
bucketAttr[i] = {}
end
-- 每个桶数据大小的区间范围
local gap = math.floor((maxNum-minNum)/bucketCnt)+1
-- 按大小范围存入不同桶中
for i=1, #t do
local idx = math.floor(t[i]/gap) + 1
bucketAttr[idx][#bucketAttr[idx]+1] = t[i]
end
-- printTable(bucketAttr)
-- 对桶内元素排序
for i=1, bucketCnt do
selectSort(bucketAttr[i])
end
-- 合并
local finTable = {}
for i=1, #bucketAttr do
for j=1, #bucketAttr[i] do
finTable[#finTable+1] = bucketAttr[i][j]
end
end
return finTable
end
ttt = {4,9,2,8,0,5,6,3,7,1}
print("before:")
print(table.concat(ttt,","))
local fin = bucketSort(ttt)
print("after:")
print(table.concat(fin,","))
计数排序
-- countingSort
--[[ 计数排序 要求被排序的数据必须为>0的整数
因为计数排序是将数据作为一个哈希表的key存入的 t[number] = cnt
被排序的数中每出现一个number,cnt++
最后对cnt>1的值,从小到大按顺序输出cnt次对应的number 就是排序后的数组
]]
-- 计数排序其实就是空间换效率的排序方式,要根据排序数组中的最大最小值范围确定空间
-- 时间复杂度 O(n+k) k是待排序列最大值
-- 空间复杂度 O(k)
function countingSort(t)
local maxNum = t[1]
local minNum = t[1]
local idxTable = {}
for i,v in ipairs(t) do
maxNum = math.max(maxNum, v)
minNum = math.min(minNum, v)
end
for i=minNum, maxNum do
idxTable[i] = 0
end
for i,v in ipairs(t) do
if idxTable[i] then
idxTable[i] = idxTable[i] + 1
end
end
local tarTable = {}
for i=minNum, maxNum do
while idxTable[i] > 0 do
tarTable[#tarTable+1] = i
idxTable[i] = idxTable[i] - 1
end
end
return tarTable
end
ttt = {4,9,2,8,5,6,3,7,1}
print("before:")
print(table.concat(ttt,","))
local fin = countingSort(ttt)
print("after:")
print(table.concat(fin,","))
基数排序
-- radixSort
-- 基数排序是基于桶排序和计数排序的思想 基础的只能对正整数组进行排序
-- 分配9个桶的哈希表,获取数组中每个数的第X位的数作为桶的idx按顺序放入桶
-- 然后按桶的idx顺序0-9返回给数组。继续X++,按顺序返回给数组,最后没有>X位的数了 排序完成
-- 时间复杂度 O(n*k) k是元素位数 空间复杂度 O(n)
function radixSort(t)
local bit = 1
local vector = {}
-- 找出最大值
local maxNum = t[1]
for i=1, #t do
maxNum = math.max(maxNum, t[i])
end
while math.floor(maxNum / bit) % 10 > 0 do -- 根据最大值的位数确定遍历次数
-- 初始化桶
for i=0, 9 do
vector[i] = {}
end
for i=1, #t do
-- 获得该数中bit位置的数 作为桶索引插入
local remd = math.floor(t[i] / bit) % 10
vector[remd][#vector[remd]+1] = t[i]
end
bit = bit * 10
local len=1
for i=0, 9 do
for j=1, #vector[i] do
t[len] = vector[i][j]
len = len + 1
end
end
end
end
ttt = {44,9999,2,888,10,53,643,359,4378,123}
print("before:")
print(table.concat(ttt,","))
radixSort(ttt)
print("after:")
print(table.concat(ttt,","))
归并排序
-- 归并排序 递归和合并
-- 复杂度 0(n*logN)
-- start到mid和mid+1到end的数据是已经排好序的,将整个t排好序
function merge(t, start, mid, tail)
local tempT = {}
local p1 = start
local p2 = mid + 1
while p1 <= mid and p2 <= tail do
if t[p1] and t[p2] then -- 注意越界
if t[p1] <= t[p2] then
tempT[#tempT+1] = t[p1]
p1 = p1 + 1
else
tempT[#tempT+1] = t[p2]
p2 = p2 + 1
end
end
end
if p1 <= mid then
for i=p1, mid do
tempT[#tempT+1] = t[i]
end
end
if p2 <= tail then
for i=p2, mid do
tempT[#tempT+1] = t[i]
end
end
for i, v in ipairs(tempT) do
t[start+i-1] = tempT[i]
end
end
function sort(t, start, tail)
if start >= tail then return end
local mid = math.floor((start+tail)/2) -- 这里必须向下取整,因为122时p2=3 进入不了循环
-- 分
sort(t, start, mid) -- 将左半边递归排序
sort(t, mid+1, tail) -- 将右半边递归排序
-- 治
merge(t, start, mid, tail) -- 将整个数组排序
end
ttt = {4,9,2,8,5,6,3,7,1}
print("before:")
print(table.concat(ttt,","))
sort(ttt, 1, #ttt)
print("after:")
print(table.concat(ttt,","))
快速排序
-- quickSort
--[[
另外一种递归的方式,从列表中取一个基准数,遍历数组将小于和大于基准数的数
分别放到不同区间范围,基准数放在中间,利用递归的思想,将两边的数再进行取基准
分两边的操作,直到递归完。
]]
-- 时间复杂度 O(n*logn) 空间复杂度 O(1)
function getPivot(t, start, tail)
local pivot = start
local biggerIdx = start + 1
-- 保证<biggerIdx的前面都是小于pivot的数 不包含t[biggerIdx]
for i=start+1, tail do
if t[i] <= t[pivot] then
t[i], t[biggerIdx] = t[biggerIdx], t[i]
biggerIdx = biggerIdx + 1
end
end
-- t[biggerIdx] 是大于t[pivot]的
t[pivot], t[biggerIdx-1] = t[biggerIdx-1], t[pivot]
pivot = biggerIdx - 1
return pivot
end
function quickSort(t, start, tail)
if start >= tail then return end
local pivot = getPivot(t, start, tail)
quickSort(t, start, pivot-1)
quickSort(t, pivot+1, tail)
end
ttt = {4,9,2,8,5,6,3,7,1}
print("before:")
print(table.concat(ttt,","))
quickSort(ttt, 1, #ttt)
print("after:")
print(table.concat(ttt,","))