Stack = class("Stack");
function Stack:ctor()
self.container = {};
end
function Stack:push(item)
table.insert(self.container, item);
end
function Stack:pop()
return table.remove(self.container);
end
function Stack:peek()
return self.container[self:count()]
end
function Stack:clear()
self.container = {};
end
function Stack:count()
return #self.container;
end
function Stack:iter()
local i = self:count() + 1;
return function()
i = i - 1;
return self.container[i];
end
end
local function testStack()
local s = Stack.new();
s:push(1);
s:push(2);
s:push(3);
for val in s:iter() do
print(val);
end
assert(s:count() == 3);
assert(s:pop() == 3);
assert(s:peek() == 2);
assert(s:pop() == 2);
assert(s:count() == 1);
assert(s:pop() == 1);
assert(s:count() == 0);
end
Queue = class("Queue");
function Queue:ctor()
self.container = {};
end
function Queue:enqueue(item)
table.insert(self.container, item);
end
function Queue:dequeue()
return table.remove(self.container, 1);
end
function Queue:peek()
return self.container[self:count()]
end
function Queue:iter()
local i = 0;
return function()
i = i + 1;
return self.container[i];
end
end
function Queue:clear()
self.container = {};
end
function Queue:count()
return #self.container;
end
local function testQueue()
local s = Queue.new();
s:enqueue(1);
s:enqueue(2);
s:enqueue(3);
for val in s:iter() do
print(val);
end ;
for val in s:iter() do
print(val);
end ;
assert(s:count() == 3);
assert(s:dequeue() == 1);
assert(s:dequeue() == 2);
assert(s:peek() == 3);
assert(s:count() == 1);
s:enqueue(4);
assert(s:count() == 2);
s:clear();
assert(s:count() == 0);
end
LinkedListNode = class("LinkedListNode");
LinkedList = class("LinkedList");
function LinkedListNode:ctor(val)
self.value = val;
self.next = false;
end
function LinkedList:addLast(val)
local node = LinkedListNode.new(val);
if self.first == nil then
self.first = node;
else
local temp = self.first;
while temp.next do
temp = temp.next;
end
temp.next = node;
end
end
function LinkedList:clear()
self.first = nil;
end
function LinkedList:iter()
local i = 0;
return function()
i = i + 1;
return self:indexOf(i);
end
end
function LinkedList:indexOf(oneStartIndex)
local i = 0;
local temp = self.first;
while temp do
i = i + 1;
if i == oneStartIndex then
return temp;
end
temp = temp.next;
end
return nil;
end
function LinkedList:count()
res = 0;
local temp = self.first;
while temp do
res = res + 1;
temp = temp.next;
end
return res;
end
function LinkedList:addAfter(oneStartIndex, newVal)
if oneStartIndex < 1 then
error("index error")
end
local curNode = self:indexOf(oneStartIndex);
local newNode = LinkedListNode.new(newVal);
local curNodeNext = curNode.next;
curNode.next = newNode;
newNode.next = curNodeNext;
end
function LinkedList:remove(oneStartIndex)
if oneStartIndex == 1 then
error("nonsupport remove firstNode");
end
local prevNode = self:indexOf(oneStartIndex - 1);
local removeNode = prevNode.next;
prevNode.next = prevNode.next.next;
return removeNode;
end
local function testLinkedList()
local l = LinkedList.new();
l:addLast("a");
l:addLast("b");
l:addLast("c");
local node = l.first;
local node2 = l.first;
while node do
print(node.value);
node = node.next;
end
while node2 do
print(node2.value);
node2 = node2.next;
end
for val in l:iter() do
print(val.value);
end
for val in l:iter() do
print(val.value);
end
assert(l:count() == 3);
assert(l:remove(2).value == "b");
l:addAfter(2, "d");
assert(l:count() == 3);
l:addAfter(2, "e");
l:remove(3);
for val in l:iter() do
print(val.value);
end
for val in l:iter() do
print(val.value);
end
assert(l:count() == 3);
l:clear();
assert(l:count() == 0);
end
--二叉搜索树
BinaryTreeNode = class("BinaryTreeNode");
function BinaryTreeNode:ctor(val)
self.value = val;
self.left = nil;
self.right = nil;
end
---@class BinarySearchTree
BinarySearchTree = class("BinarySearchTree");
function BinarySearchTree:ctor()
end
function BinarySearchTree:GetSuitNodeAndInsert(val)
local root = self.root;
local function dfs(node, value)
if node == nil then
return nil;
end
if value >= node.value and node.right then
return dfs(node.right, value);
end
if value < node.value and node.left then
return dfs(node.left, value);
end
return node;
end
local parentNode = dfs(root, val);
if val >= parentNode.value then
parentNode.right = BinaryTreeNode.new(val);
else
parentNode.left = BinaryTreeNode.new(val);
end
end
function BinarySearchTree:Add(val)
if self.root == nil then
self.root = BinaryTreeNode.new(val);
else
self:GetSuitNodeAndInsert(val);
end
end
local function Inorder(rootNode)
local root = rootNode;
local function dfs(node)
if node == nil then
return
end
dfs(node.left);
print(node.value);
dfs(node.right);
end
dfs(root);
end
function BinarySearchTree:AddByArray(arr)
for i, v in ipairs(arr) do
self:Add(v);
end
end
function BinarySearchTree:Search(val)
local root = self.root;
local function dfs(node, value)
if node == nil then
return nil;
end
if value > node.value and node.right then
return dfs(node.right, value);
end
if value < node.value and node.left then
return dfs(node.left, value);
end
if value == node.value then
return node;
else
return nil;
end
end
return dfs(root, val);
end
function BinarySearchTree:FindParent(childNode)
local root = self.root;
local function dfs(node, cNode)
if node == nil then
return nil;
end
if node.left and node.left == cNode then
return node;
end
if node.right and node.right == cNode then
return node;
end
if cNode.value > node.value and node.right then
return dfs(node.right, cNode);
end
if cNode.value < node.value and node.left then
return dfs(node.left, cNode);
end
end
if childNode == root then
error("Don't support find root node");
end
return dfs(root, childNode);
end
--[[
分3种情况讨论
情况一:被删除node没有子节点
1.找到该node节点
2.(a.暂时不支持删除根节点,b.要删除的节点刚好仅为一个root节点)
3. 找到该节点的父节点p
4. 判断该节点是p的左还是右
5. p.left =nil;或者p.right =nil;
情况二:被删除node有1个节点
1.找到该node节点
2.(a.暂时不支持删除根节点,b.要删除的节点刚好仅为一个root节点)
3. 找到该节点的父节点p
4. 判断该节点是p的左还是右
5. 分为好几种情况,直接指向就行了,因为是1个节点。不需要类似情况三的赋值删除。
情况三:被删除node有两个节点
1.找到该node节点
2.(a.暂时不支持删除根节点,b.要删除的节点刚好仅为一个root节点)
3. 找到该节点的父节点p
4. 判断该节点是p的左还是右
5. 把node值改为它左子树中最大的节点就行了,对左右两边都有用,没有if分支判断的
6. 把最小的node删除
]]
function BinarySearchTree:FindLeftMaxNode(curNode)
local temp = curNode.left;
while temp.right ~= nil do
temp = temp.right;
end
return temp.value;
end
function BinarySearchTree:FindRightMinNode(curNode)
local temp = curNode.right;
while temp.left ~= nil do
temp = temp.left;
end
return temp.value;
end
function BinarySearchTree:Delete(val)
local node = self:Search(val);
if node == nil then
return ;
end
local parent = self:FindParent(node);
if node.left == nil and node.right == nil then
if parent.left ~= nil and parent.left == node then
parent.left = nil;
end
if parent.right ~= nil and parent.right == node then
parent.right = nil;
end
elseif node.left ~= nil and node.right ~= nil then
local maxValue = self:FindRightMinNode(node);
self:Delete(maxValue);
node.value = maxValue;
else
if parent.left ~= nil and parent.left == node then
if node.left ~= nil then
parent.left = node.left;
else
parent.left = node.right;
end
end
if parent.right ~= nil and parent.right == node then
if node.left ~= nil then
parent.right = node.left;
else
parent.right = node.right;
end
end
end
end
function BinarySearchTree:DFS()
local root = self.root;
local stack = Stack.new();
local cur = root;
local top = nil;
while cur or stack:count() > 0 do
while cur do
stack:push(cur);
cur = cur.left;
end
top = stack:pop();
print(top.value);
cur = top.right;
end
end
function BinarySearchTree:BFS()
local root = self.root;
local que = Queue.new();
que:enqueue(root);
while que:count() > 0 do
local first = que:dequeue();
print(first.value);
if first.left then
que:enqueue(first.left);
end
if first.right then
que:enqueue(first.right);
end
end
end
local function testBinarySearchTree()
---@type BinarySearchTree
local g = BinarySearchTree.new();
local data = { 7, 3, 10, 12 };
local data2 = { 5, 1, 9 };
g:AddByArray(data);
g:AddByArray(data2);
--g:Delete((1));
--Inorder(g.root);
g:DFS();
end
--todo 有缺陷应该用面向对象写法,加上data,children,isEnd
Trie = class("Trie")
function Trie:ctor()
self.root = {};
end
function Trie:save(str)
local root = self.root;
for i = 1, #str do
local single = string.sub(str, i, i);
local singleNum = string.byte(single:lower());
local singleNumIndex = singleNum - 97 + 1;
if root[singleNumIndex] == nil then
root[singleNumIndex] = single;
end ;
if root.children == nil then
root.children = {};
end
root = root.children;
end
end
function Trie:fetch(strPrefix)
local res = {};
local root = self.root;
for i = 1, #strPrefix do
local single = string.sub(strPrefix, i, i);
local singleNum = string.byte(single:lower());
local singleNumIndex = singleNum - 97 + 1;
if root[singleNumIndex] == nil then
return res;
else
root = root.children;
end
end
for i, v in pairs(root) do
if type(v) == "table" then
goto continue
end
table.insert(res, strPrefix .. tostring(v));
:: continue ::
end
return res;
end
local function testTrie()
local t = Trie.new();
t:save("ABC");
t:save("ABD");
t:save("BD");
t:save("BCE");
local res = t:fetch("B");
for i, v in ipairs(res) do
print(v);
end
end
--贪心算法:策略是保留更多的5,因为5比10用到的机会更多
local function LemonadeChange(bills)
local fives = {};
local tens = {};
for i, v in ipairs(bills) do
if v == 5 then
table.insert(fives, 5);
elseif v == 10 then
table.insert(tens, 10);
if #fives ~= 0 then
table.remove(fives, 1);
else
return false;
end
elseif v == 20 then
if #tens ~= 0 then
table.remove(tens, 1);
if #fives ~= 0 then
table.remove(fives, 1);
else
return false;
end
else
if #fives ~= 3 then
return false;
end
end
end
end
return true;
end
local function testLemonadeChange()
assert(LemonadeChange({ 5, 5, 5, 10, 20 }) == true);
assert(LemonadeChange({ 5, 5, 10 }) == true);
assert(LemonadeChange({ 10, 20 }) == false);
assert(LemonadeChange({ 5, 5, 10, 10, 20 }) == false);
end
--动态规划最大子序列和
local function MaxSubArray()
local nums = { -2, 1, -3, 4, -1, 2, 1, -5, 4 };
local dp = {};
dp[1] = nums[1];
local res = nums[1];
for i = 2, #nums do
dp[i] = math.max(dp[i - 1] + nums[i], nums[i]);
res = math.max(res, dp[i]);
end
assert(res == 6);
end
--经典回溯
local function AllSort()
local arr = { "a", "b", "c" };
local count = #arr;
local paths = {};
local used = {};
for i = 1, count do
used[i] = false;
end
local function getPath(t)
return table.concat(t);
end
local function recursion(depth, pathTable)
if depth == count then
table.insert(paths, table.concat(pathTable))
return ;
end
for i = 1, count do
if used[i] then
goto continue
end
table.insert(pathTable, arr[i]);
used[i] = true;
recursion(depth + 1, pathTable);
table.remove(pathTable);
used[i] = false;
:: continue ::
end
end
recursion(0, {});
for i, v in ipairs(paths) do
print(v);
end
end
--分治思想
local function MergeTwoLists(list1, list2)
local l1 = LinkedList.new();
l1:addLast(1);
l1:addLast(2);
l1:addLast(4);
l1:addLast(5);
local l1Node = l1.first;
local l2 = LinkedList.new();
l2:addLast(1);
l2:addLast(3);
l2:addLast(4);
l2:addLast(4);
l2:addLast(4);
l2:addLast(4);
local l2Node = l2.first;
local node = LinkedListNode.new(0);
local temp = node;
local cur;
while l1Node and l2Node do
if l1Node.value <= l2Node.value then
cur = LinkedListNode.new(l1Node.value);
l1Node = l1Node.next;
else
cur = LinkedListNode.new(l2Node.value);
l2Node = l2Node.next;
end
temp.next = cur;
temp = temp.next;
end
temp.next = l1Node and l1Node or l2Node;
local test = node.next;
while test do
print(test.value);
test = test.next;
end
end
local function binarySearch(t, searchVal)
local l = 1;
local r = #t;
while l <= r do
local midIndex = (l + r) // 2;
local midVal = t[midIndex];
if midVal == searchVal then
return midIndex;
elseif midVal < searchVal then
l = midIndex + 1;
else
r = midIndex - 1;
end
end
return 0;
end
local function testBinarySearch()
local t = { 1, 2, 3, 4, 9, 20, 100, 999 };
assert(binarySearch(t, 9) == 5);
assert(binarySearch(t, 999) == 8);
assert(binarySearch(t, 1) == 1);
assert(binarySearch(t, 100) == 7);
assert(binarySearch(t, 1200) == 0);
end
local function StringMatching(strSrc, strPattern)
local moveCount = #strSrc - #strPattern + 1;
local pCount = #strPattern;
local function GetSub(str, index)
return string.sub(str, index, index);
end
for i = 1, moveCount do
local count = 0;
for j = 1, pCount do
if GetSub(strPattern, j) == GetSub(strSrc, j + i - 1) then
count = count + 1;
else
break ;
end
end
if count == pCount then
return true;
end
end
return false;
end
local function testStringMatching()
assert(StringMatching("hello world", "horl") == false)
assert(StringMatching("hello world", "ll wo") == false)
assert(StringMatching("hello world", "lo w") == true)
assert(StringMatching("hello world", "hel") == true)
assert(StringMatching("hello world", "o world") == true)
assert(StringMatching("hello world", "rld") == true)
assert(StringMatching("hello world", "llo wor") == true)
assert(StringMatching("hello world", "hello world") == true)
assert(StringMatching("hello world", "o lo") == false)
assert(StringMatching("hello world", "rd") == false)
assert(StringMatching("hello world", "he") == true)
assert(StringMatching("hello world", "ld") == true)
assert(StringMatching("hello world", "llo") == true)
end
local function popSort(t)
for i = 1, #t - 1 do
for j = i + 1, #t do
if t[i] > t[j] then
t[i], t[j] = t[j], t[i];
end
end
end
end
local function selectSort(t)
for i = 1, #t - 1 do
local minVal = t[i];
local minIndex = i;
for j = i + 1, #t do
if t[j] < minVal then
minVal = t[j];
minIndex = j;
end
end
t[i], t[minIndex] = t[minIndex], t[i];
end
end
local function insertSort(t)
for i = 2, #t do
local insertVal = t[i];
local insertValPrevIndex = i - 1;
while insertValPrevIndex >= 1 and insertVal < t[insertValPrevIndex] do
t[insertValPrevIndex + 1] = t[insertValPrevIndex];
insertValPrevIndex = insertValPrevIndex - 1;
end
t[insertValPrevIndex + 1] = insertVal;
end
end
local function countSort(t)
local tableModel = {};
local res = {};
for i = 1, 10 do
tableModel[i] = 0;
end
for i, v in ipairs(t) do
tableModel[v] = tableModel[v] + 1;
end
local jj = 1;
for i = 1, #tableModel do
for j = 1, tableModel[i] do
res[jj] = i;
jj = jj + 1;
end
--[[ while tableModel[i] > 0 do
table.insert(res, v);
tableModel[i] = tableModel[i] - 1;
end]]
end
return res;
end
local function cardinal(numss)
local maxLength = 3;
local numStrs = {};
local function addZero(num)
local res = "";
local selfLen = string.len(tostring(num));
for i = 1, maxLength - selfLen do
res = res .. "0";
end
return res .. tostring(num);
end
for i = 1, #numss do
table.insert(numStrs, addZero(numss[i]));
end
local model = {}
for i = 1, 10 do
model[tostring(i - 1)] = Queue.new();
end
local function put(putStr, currentCardinal)
local subIndex = (maxLength - currentCardinal) + 1;
local key = string.sub(putStr, subIndex, subIndex);
local queue = model[key];
queue:enqueue(putStr);
end
local function fetch()
end
for i = 1, maxLength do
for j = 1, #numStrs do
local firNum = table.remove(numStrs, 1);
put(firNum, i);
j = j - 1;
end
for i = 1, 10 do
local key = tostring(i - 1);
while model[key]:count() > 0 do
local val = model[key]:dequeue();
table.insert(numStrs, val);
end
end
end
return numStrs;
end
local function bucketSort(t)
local t = { 8, 2, 3, 5, 1, 7, 11, 4 };
local range = (1 + 11) / 2;
local t1 = {};
local t2 = {};
for i = 1, #t do
if t[i] >= 1 and t[i] <= range then
table.insert(t1, t[i]);
else
table.insert(t2, t[i]);
end
end
table.sort(t1);
table.sort(t2);
for i = 1, #t2 do
table.insert(t1, t2[i])
end
printTable(t1);
end
local function mergeTwoTable(t1, t2)
t1 = t1 or {};
t2 = t2 or {};
local res = {};
local p1 = 1;
local p2 = 1;
while p1 <= #t1 and p2 <= #t2 do
if t1[p1] <= t2[p2] then
table.insert(res, t1[p1]);
p1 = p1 + 1;
else
table.insert(res, t2[p2]);
p2 = p2 + 1;
end
end
for i = p1, #t1 do
table.insert(res, t1[i]);
end
for i = p2, #t2 do
table.insert(res, t2[i]);
end
return res;
end
local function MergeSort(t)
local len = #t;
local res = {};
for i = 1, len do
local t = { t[i] };
table.insert(res, t);
end
repeat
local temp = {};
for i = 1, #res, 2 do
local mergeT = mergeTwoTable(res[i], res[i + 1]);
table.insert(temp, mergeT);
end
res = temp;
until (#res == 1)
res = res[1];
return res;
end
local function GetAllPrefix(strModel)
local res = {}
for i = 1, #strModel - 1 do
local str = string.sub(strModel, 1, i);
table.insert(res, str);
end
return res;
end
local function GetAllSuffix(strModel)
local res = {}
for i = 2, #strModel do
local str = string.sub(strModel, i);
table.insert(res, str);
end
local res2 = {};
while #res > 0 do
table.insert(res2, table.remove(res))
end
return res2;
end
local function GetLongestEqualPrefixAndSuffix(t1, t2)
local res = 0;
local count = #t1;
for i = count, 1, -1 do
if t1[i] == t2[i] then
return #t1[i];
end
end
return res;
end
local function KMPGetPrefixTable(strModel)
local res = {};
local allPrefix = GetAllPrefix(strModel);
local nums = {};
for i, v in ipairs(allPrefix) do
local allPrefiix = GetAllPrefix(v);
local allsuffix = GetAllSuffix(v);
local longestEqualPrefixAndSuffix = GetLongestEqualPrefixAndSuffix(allPrefiix, allsuffix);
table.insert(nums, longestEqualPrefixAndSuffix);
end
table.insert(nums, 0);
return nums;
end
local function kmpGetaddReduceNum(prefixTable, charKey)
return prefixTable[charKey - 1];
end
--Todo 有问题暂时放弃了
local function kmpMatching(strSrc, strPattern)
local prefixTable = KMPGetPrefixTable(strPattern);
local moveCount = #strSrc - #strPattern + 1;
local pCount = #strPattern;
local function GetSub(str, index)
return string.sub(str, index, index);
end
local i = 1;
while i <= moveCount do
local count = 0;
local charKey;
for j = 1, pCount do
charKey = j;
if GetSub(strPattern, j) == GetSub(strSrc, j + i - 1) then
count = count + 1;
else
break ;
end
end
if count == pCount then
return true;
end
local add = 1;
if count > 0 then
add = count - kmpGetaddReduceNum(prefixTable, charKey);
end
i = i + add;
end
return false;
end
local function heapify(tree, n, i)
if i > n then
return ;
end
local c1 = 2 * i;
local c2 = 2 * i + 1;
local max = i;
if c1 <= n and tree[c1] > tree[max] then
max = c1;
end
if c2 <= n and tree[c2] > tree[max] then
max = c2;
end
if max ~= i then
swap(tree, max, i);
heapify(tree, n, max);
end
end
local function buildHeap(tree, n)
local last = n;
local parent = last / 2;
for j = parent, 1, -1 do
heapify(tree, n, j);
end
end
--//待完善
local function HeapSort(t)
buildHeap(t, #t);
for i = #t, 1, -1 do
swap(t, i, 0);
heapify(t, i, 0);
end
printTable(t);
end
local function testHeapSort()
local tree = { 4, 10, 3, 5, 1, 2 };
HeapSort(tree);
end
Lua待完善的算法数据结构代码(不一定正确)
于 2021-01-27 15:51:18 首次发布