Lua待完善的算法数据结构代码(不一定正确)





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






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值