【lua】用LUA学习排序不会很奇怪吗---------lua数组默认从1计数

前言

冒泡、冒泡改进、鸡尾酒、快速……
话说,用lua做这些算法不会很奇怪吗?也许有lua模块可以进行更快的排序吧!在写这篇也算是学习(复习)一下lua了,在实现了几个排序后可能会加一下特殊点的语法。
(用的是sublime text编译)


基本显示

print('hello lua developer\n基本显示')

a={
    
    1,8,9,10,'a',3,2,6,7,4,5,'hello'} --lua数据结构,表table,可代替类
print(#a)

--[[
多行注释

#a表示求a中的数字或字符串的个数
..表示字符串的拼接
]]
for i=1,#a do --单行注释   默认步长为1
	io.write(i..'>') --输出后没换行
	for j=1,i do
		io.write(a[j]..' ')
	end
	print() --输出后有换行
end

输出为

hello lua developer
基本显示
12
1>1 
2>1 8 
3>1 8 9 
4>1 8 9 10 
5>1 8 9 10 a 
6>1 8 9 10 a 3 
7>1 8 9 10 a 3 2 
8>1 8 9 10 a 3 2 6 
9>1 8 9 10 a 3 2 6 7 
10>1 8 9 10 a 3 2 6 7 4 
11>1 8 9 10 a 3 2 6 7 4 5 
12>1 8 9 10 a 3 2 6 7 4 5 hello 
[Finished in 0.1s]

冒泡排序

在这里插入图片描述
一组乱序的数据,通过两两相邻的交换直到全部排序完成!
就像气泡从水里升起一样!
如果外部索引从头到尾刷过去,那么内部索引就像上面那样,从头到尾且长度逐渐减少。之所以这样是因为第一步就把最大的排到了最后,第二步就把第二大的排到了倒数第二个,所以内部索引刷新的长度就没必要去刷已排序完成的部分了
如果外部索引的刷新顺序是从尾到头,那么内部索引就相反。

  • lua语言是从1开始索引的,但是区别不大!
print('hello lua developer\n冒泡排序')

local function showArray(arr) --局部函数
	for i=1,#arr do
		io.write(arr[i])
		--等距输出
		if arr[i]>9 then
			io.write(' ')
		else 
			io.write('  ')
		end
	end
	print()
end


arr={
    
    1,8,9,10,3,2,6,7,4,5}
showArray(arr)
for i=1,#arr do
	for j=1,#arr-i do
		if arr[j]>arr[j+1] then
			temp=arr[j]
			arr[j]=arr[j+1]
			arr[j+1]=temp
		end
	end
end
showArray(arr)

输出为

hello lua developer
冒泡排序
1  8  9  10 3  2  6  7  4  5  
1  2  3  4  5  6  7  8  9  10 
[Finished in 0.3s]

冒泡排序改进1,提前结束

内部索引第一轮是从开头刷新到末尾,最后一轮是刷新第一个到第二个,但是如果到最后一轮前,前面两个就已经是排序好的了,那么最后一轮就是浪费!
所以说,需要提前结束排序——在一轮内部刷新没有交换元素的情况下(已经排序完成)

for i=1,#arr do
	isSorted=true
	for j=1,#arr-i do
		if arr[j]>arr[j+1] then
			temp=arr[j]
			arr[j]=arr[j+1]
			arr[j+1]=temp
			isSorted=false --有元素交换,没有排序完
		end
	end
	if isSorted then --上一轮没有元素交换,已经排序完成
		break
	end
end

冒泡排序改进2,设置有序边界

之前是提前结束,算是设置了左边界,现在我们来设置右边界。
每次开始的阶段都是从头到尾,这也不xing哎!我们可以设置从头到sortBorder——比如本来是刷新到7,现在设置了右边界后刷新到4,当然是在5,6,7都排序好时,这样效率就更高了点。

lastExchangeIndex=1
sortBorder=#arr-1
for i=1,#arr do
	isSorted=true
	for j=1,sortBorder do
		if arr[j]>arr[j+1] then
			temp=arr[j]
			arr[j]=arr[j+1]
			arr[j+1]=temp
			isSorted=false --有元素交换,没有排序完
			lastExchangeIndex=j --更新为最后一次交换元素的位置
		end
	end
	sortBorder=lastExchangeIndex --更新边界
	if isSorted then --上一轮没有元素交换,已经排序完成
		break
	end
end

鸡尾酒排序

在这里插入图片描述
左右都在冒泡,左边冒一会儿泡,右边冒一会儿泡,就像摇鸡尾酒一样(大概吧)
鸡尾酒排序就是冒泡排序·改,可以在大部分元素已经有序的情况下,发挥其优势!

for i=1,#arr/2 do
	isSorted=true
	--从左到右
	for j=i,#arr-i do
		if arr[j]>arr[j+1] then
			temp=arr[j]
			arr[j]=arr[j+1]
			arr[j+1]=temp
			isSorted=false
		end
	end
	if isSorted then
		break
	end
	--从右到左
	for j=#arr-i+1,i+1,-1 do
		if arr[j-1]>arr[j] then
			temp=arr[j]
			arr[j]=arr[j-1]
			arr[j-1]=temp
			isSorted=false
		end
	end
	if isSorted then
		break
	end
end

鸡尾酒排序改进1,设置有序边界


leftBorder=2
leftLastExchangeIndex=#arr
rightBorder=#arr-1
rightLastExchangeIndex=1
for i=1,#arr/2 do
	isSorted=true
	--从左到右
	for j=leftBorder,rightBorder do
		if arr[j]>arr[j+1] then
			temp=arr[j]
			arr[j]=arr[j+1]
			arr[j+1]=temp
			isSorted=false
			rightLastExchangeIndex=j
		end
	end
	rightBorder=rightLastExchangeIndex
	if isSorted then
		break
	end
	--从右到左
	for j=rightBorder,leftBorder,-1 do
		if arr[j-1]>arr[j] then
			temp=arr[j]
			arr[j]=arr[j-1]
			arr[j-1]=temp
			isSorted=false
			leftLastExchangeIndex=j
		end
	end
	leftBorder=leftLastExchangeIndex
	if isSorted then
		break
	end
end


快速排序

快速排序有好几种实现的方法,总的来说,利用了分治的思想的排序就是快速排序!
分治类似于二分法,一分二,二分四,四份八

双边循环的快速排序

在这里插入图片描述

先从一组数据中取一个做基准元素,一般取第一个或者是随机取一个。
然后设置两个指针,一个从头刷新到尾,一个从尾刷新到头,左边的指针找到大于基准元素的,右边找到小于基准元素的,然后交换一下——这样就可以实现把小于基准元素的都放一边,然后递归下去,就可以把整个数据都排序好!


local function partition(arr,startIndex,endIndex)
	--[[
		取第一个位置的元素做基准元素
		当然,如果第一个元素是最大的或最小的,时间复杂度就很高了
	]]
	pivot=arr[startIndex]
	leftPointer=startIndex  --左指针,负责在左边找大于基准元素的
	rightPointer=endIndex  --右指针,负责在右边找小于基准元素的

	while leftPointer~=rightPointer do --lua不等于为~=
		while leftPointer<rightPointer and arr[rightPointer]>pivot do
			rightPointer=rightPointer-1
		end
		while leftPointer<rightPointer and arr[leftPointer]<=pivot do
			leftPointer=leftPointer+1
		end
		--找到了,把小的元素放到左边,大的元素放到右边
		if leftPointer<rightPointer then
			temp=arr[leftPointer]
			arr[leftPointer]=arr[rightPointer]
			arr[rightPointer]=temp
		end
	end


	--从循环里出来时,leftPointer和rightPointer重合了,所以把基准元素(第一个元素)交换到中间去
	arr[startIndex]=arr[leftPointer]
	arr[leftPointer]=pivot

	--返回中间元素
	return leftPointer
end

local function quicksort(arr,startIndex,endIndex)
	if startIndex>=endIndex then --递归结束条件,一般都放前面
		return
	end
	--取得基准元素,并排序
	pivotIndex=partition(arr,startIndex,endIndex)
	--根据基准元素,分成两个部分进行递归
	quicksort(arr,startIndex,pivotIndex-1)
	quicksort(arr,pivotIndex+1,endIndex)
end



arr={
    
    1,8,9,10,3,2,6,7,4,5}
showArray(arr)
quicksort(arr,1,#arr)
showArray(arr)

输出

hello lua developer
快速排序
1  8  9  10 3  2  6  7  4  5  
1  2  3  4  5  6  7  8  9  10 
[Finished in 0.1s]

单边循环的快速排序

相似的道理,没必要设置两个指针,一个指针也可以。在左边设置一个指针,从左刷新到右,遇到比基准大的就继续右移,遇到小于基准的就交换到此指针左边去!


local function partition(arr,startIndex,endIndex)
	pivot=arr[startIndex]
	mark=startIndex

	--从第二个元素开始往右刷
	for i=startIndex+1,endIndex do
		if arr[i]<pivot then --每次遇到一个小于基准的,就把它交换到mark左边
			mark=mark+1
			temp=arr[mark]
			arr[mark]=arr[i]
			arr[i]=temp
		end
	end

	--mark指针停住了,意思是已经把小的放在了左边,大的放在了右边
	--所以,此时把基准元素交换到mark位置来
	arr[startIndex]=arr[mark]
	arr[mark]=pivot
	return mark
end

非递归的快速排序

递归与栈可以相互代替,所以不用函数递归就用栈的抛出和压进!

先用lua模块编写的方法做一个stack的数据结构,不止可以压入数据,还能压入对象!
这处的难点在于如何拷贝table!

  • 我只做了一个简单的保存数据的栈,没有实现保存表的功能┭┮﹏┭┮
--[[
用lua做的数据结构栈module.lua

lua中的基本类型、函数都是值传递,只有表是引用传递

直接用stack=require "stack"来接收模块,可以得到默认的一个空栈
想要拷贝的话就用a=copy(stack)

lua中的#table只算其中的数字和字符串的数量
]]

local module={
    
    }
module.info='stack_2019_12_7@demllie'
module.top=0 --记的是栈中的一级总数,如果某个元素是表,那么下面的元素不计
function push(self,data)
	--print('push')
	if type(data)~='number' then
		print('error:data isn\'t number')
		return -1
	end
	self.top=self.top+1  
	self[self.top]=data	
end

function pop(self)
	--print('pop')
	if self.top==0 then
		print('error:top is zero, can\'t pop data')
		return -1
	end
	data=self[self.top]
	table.remove(self) --默认删除最后一个元素
	self.top=self.top-1
	return data
end

function isEmpty(self)
	--print('isEmpty')
	return self.top==0
end
function getNum(self)
	return self.top
end


function showArray(self) 
	io.write('showArray>')
	for i=1,#self do
		io.write(self[i])
		--等距输出
		if self[i]>9 then
			io.write(' ')
		else 
			io.write('  ')
		end	
	end
	print()
end



--拷贝一个表
function copy(self)
    local function table_copy(src, dst)
        for k,v in pairs(src) do
            if type(v) == "table" then
                dst[k] = {
    
    }
                table_copy(v, dst[k])
            else
                dst[k] = v
            end
        end
    end	
    local  dst = {
    
    }
    table_copy(self, dst)
    return dst   
end

return module


如何使用模块 ⇓ \Downarrow

stack=require "stack"

print(stack.info)
push(stack,3)
push(stack,4)
push(stack,5)
push(stack,6)
showArray(stack)
print(pop(stack))

输出为

stack_2019_12_7@demllie
showArray>3  4  5  6  
6
[Finished in 0.3s]

非递归的快速排序,其中的partition可以是双边循环、单边循环

stack=require "stack"
local function quicksort(arr,startIndex,endIndex)

	local quicksort_stack=copy(stack)

	--栈顶元素入栈
	push(quicksort_stack,startIndex)
	push(quicksort_stack,endIndex)
	
	while isEmpty(quicksort_stack)==false do
		--出栈得到起止下标
		p2=pop(quicksort_stack)
		p1=pop(quicksort_stack)
		--得到基准元素位置
		pivot=partition(arr,p1,p2)

		--根据基准元素分成两部分
		if p1<pivot-1 then
			push(quicksort_stack,p1)
			push(quicksort_stack,pivot-1)
		end
		if pivot+1<p2 then
			push(quicksort_stack,pivot+1)
			push(quicksort_stack,p2)
		end
	end	
end

堆排序

--[[
lua做的数据结构堆heap.lua
]]

local module={
    
    }
module.info='heap_2019_12_8@demllie'


--节点下沉
function downAdjust(self,parentIndex,len)
	temp=self[parentIndex]

	--1作为开始的话,左孩子就是下面这样
	childIndex=2*parentIndex

	while childIndex<=len do
		--如果有右孩子,且右孩子大于左孩子,就定位到右孩子
		if childIndex+1 <= len and self[childIndex+1]>self[childIndex] then
			childIndex=childIndex+1
		end
		--如果父节点大于任何一个孩子的值,就跳出
		if temp >= self[childIndex] then
			break
		end

		--无需真正交换,赋值即可
		self[parentIndex]=self[childIndex]
		parentIndex=childIndex
		childIndex=2*parentIndex

	end

	self[parentIndex]=temp
end

function showArray(self) 
	io.write('showArray>')
	for i=1,#self do
		io.write(self[i])
		--等距输出
		if self[i]>9 then
			io.write(' ')
		else 
			io.write('  ')
		end	
	end
	print()
end

--堆排序
function heapSort(self)

	--1,把无序数组变成最大堆
	for i=(#self)/2,1,-1 do
		downAdjust(self,i,#self)
	end
	showArray(self)

	--2,循环删除堆顶元素,移动到尾部,调整堆产生新的堆顶
	for i=#self,1,-1 do
		temp=self[i]
		self[i]=self[1]
		self[1]=temp
		downAdjust(self,1,i-1) --堆的长度在减少,意思是末尾的被排序好了的就不算在堆内了
	end	
end

return module

使用

require "heap"
print('hello lua developer\n堆排序')

arr={
    
    1,8,9,10,3,2,6,7,4,5}
showArray(arr)
heapSort(arr)
showArray(arr)

输出为

hello lua developer
堆排序
showArray>1  8  9  10 3  2  6  7  4  5  
showArray>10 8  9  7  5  2  6  1  4  3  
showArray>1  2  3  4  5  6  7  8  9  10 
[Finished in 0.2s]

参考:《漫画算法》

猜你喜欢

转载自blog.csdn.net/weixin_41374099/article/details/103431202
LUA