commit b34bc341435fc4eab2f15daf3ac956727b39c281 Author: 3wish Date: Wed Nov 29 19:31:30 2023 +0800 stack diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cdd4b45 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.venv +test/.pytest_cache/ \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..c52158a --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,31 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..b4319e3 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..56e11be --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/pygorithm.iml b/.idea/pygorithm.iml new file mode 100644 index 0000000..eda47f2 --- /dev/null +++ b/.idea/pygorithm.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..d26c9f0 --- /dev/null +++ b/Pipfile @@ -0,0 +1,12 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +pytest = "*" + +[dev-packages] + +[requires] +python_version = "3.11" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..83c1cb2 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,61 @@ +{ + "_meta": { + "hash": { + "sha256": "922e82e69ac92d524e9aec65cbead9fdef4cdb3fcff8f459d8998bfd7bd6a67f" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.11" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "colorama": { + "hashes": [ + "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", + "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" + ], + "markers": "sys_platform == 'win32'", + "version": "==0.4.6" + }, + "iniconfig": { + "hashes": [ + "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", + "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" + ], + "markers": "python_version >= '3.7'", + "version": "==2.0.0" + }, + "packaging": { + "hashes": [ + "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", + "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" + ], + "markers": "python_version >= '3.7'", + "version": "==23.2" + }, + "pluggy": { + "hashes": [ + "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12", + "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7" + ], + "markers": "python_version >= '3.8'", + "version": "==1.3.0" + }, + "pytest": { + "hashes": [ + "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac", + "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5" + ], + "index": "pypi", + "version": "==7.4.3" + } + }, + "develop": {} +} diff --git a/stack/__pycache__/infix_conversion.cpython-311.pyc b/stack/__pycache__/infix_conversion.cpython-311.pyc new file mode 100644 index 0000000..be2b077 Binary files /dev/null and b/stack/__pycache__/infix_conversion.cpython-311.pyc differ diff --git a/stack/__pycache__/number_conversion.cpython-311.pyc b/stack/__pycache__/number_conversion.cpython-311.pyc new file mode 100644 index 0000000..0bb7cd0 Binary files /dev/null and b/stack/__pycache__/number_conversion.cpython-311.pyc differ diff --git a/stack/__pycache__/parentheses.cpython-311.pyc b/stack/__pycache__/parentheses.cpython-311.pyc new file mode 100644 index 0000000..025f39a Binary files /dev/null and b/stack/__pycache__/parentheses.cpython-311.pyc differ diff --git a/stack/__pycache__/stack.cpython-311.pyc b/stack/__pycache__/stack.cpython-311.pyc new file mode 100644 index 0000000..c62d994 Binary files /dev/null and b/stack/__pycache__/stack.cpython-311.pyc differ diff --git a/stack/infix_conversion.py b/stack/infix_conversion.py new file mode 100644 index 0000000..5baf349 --- /dev/null +++ b/stack/infix_conversion.py @@ -0,0 +1,78 @@ +""" +1. 经观察可发现操作数的相对位置是不变的,变化的只是操作符 +2. 中转前: + (1)。 如果是一个操作数,则看一眼操作符栈中的栈顶是否是 */ + (1.1). 如果是 */,则先拿到这个操作数,再从操作数栈弹出一个数 + 再弹出操作符,拼接后放入操作数栈顶 + (1.2)。如果是 +-,则将此操作数入操作数栈 + (2). 如果是一个 ( + - * /,直接入操作符栈顶 + (3). 如果是 ),则执行出栈,直到遇到 (,出栈的步骤跟 (1.1) +3. 中转后: + (1). +""" + +from .stack import Stack + + +def infix_to_prefix(infix: str): + op_stack = Stack[str]() + num_stack = Stack[str]() + + for item in infix: + if item in ['(', '*', '+', '-', '/']: + op_stack.push(item) + elif '0' <= item <= 'z': + if op_stack.peek() in ['*', '/']: + temp = num_stack.pop() + op = op_stack.pop() + num_stack.push(op + temp + item) + else: + num_stack.push(item) + elif item == ')': + op = op_stack.pop() + while op != '(': + temp1 = num_stack.pop() + temp2 = num_stack.pop() + num_stack.push(op + temp2 + temp1) + op = op_stack.pop() + if not op_stack.is_empty(): + i1 = num_stack.pop() + i2 = num_stack.pop() + op = op_stack.pop() + return op + i2 + i1 + else: + return num_stack.pop() + + +def infix_to_postfix(infix: str): + op_stack = Stack[str]() + num_stack = Stack[str]() + + for item in infix: + if item in ['(', '*', '+', '-', '/']: + op_stack.push(item) + elif '0' <= item <= 'z': + if op_stack.peek() in ['*', '/']: + temp = num_stack.pop() + op = op_stack.pop() + num_stack.push(temp + item + op) + else: + num_stack.push(item) + elif item == ')': + op = op_stack.pop() + while op != '(': + temp1 = num_stack.pop() + temp2 = num_stack.pop() + num_stack.push(temp2 + temp1 + op) + op = op_stack.pop() + if not op_stack.is_empty(): + i1 = num_stack.pop() + i2 = num_stack.pop() + op = op_stack.pop() + return i2 + i1 + op + else: + return num_stack.pop() + + +res = infix_to_prefix('a+b*c') +print(res) diff --git a/stack/number_conversion.py b/stack/number_conversion.py new file mode 100644 index 0000000..6a76df7 --- /dev/null +++ b/stack/number_conversion.py @@ -0,0 +1,24 @@ +""" +进制转换: +1. 将十进制转换为二(八、十六)进制 +2. 对2取余,余数存入栈中 +3. 将取余得的商,重复第2步,直到商为零 +4. 将栈中的数取出即是转换为二进制的结果 +""" + +from .stack import Stack + + +def decimal_to_any(num: int, base: 2 | 8 | 16) -> str: + stack = Stack[str]() + + while num > 0: + mod: int = num % base + num //= base + stack.push(str(mod)) + + res = '' + while not stack.is_empty(): + res += stack.pop() + + return res diff --git a/stack/parentheses.py b/stack/parentheses.py new file mode 100644 index 0000000..7fa4dcb --- /dev/null +++ b/stack/parentheses.py @@ -0,0 +1,27 @@ +""" +测试括号是否匹配: +1. 左括号数必须与右括号数匹配 +2. 从左到右匹配,用栈保存每个左括号 +3. 每遇到一个右括号,则左括号执行出栈操作 +4. 匹配成功:结束时若栈空则 +5. 匹配失败:栈未空(左 > 右)或者在结束之前栈已空(右 > 左) +""" + +from .stack import Stack + + +def par_match(parentheses: str) -> bool: + stack = Stack[str]() + + for i in parentheses: + if i == '(': + stack.push(i) + elif i == ')': + if stack.is_empty(): + return False + stack.pop() + + if stack.is_empty(): + return True + else: + return False diff --git a/stack/stack.py b/stack/stack.py new file mode 100644 index 0000000..4fdf43b --- /dev/null +++ b/stack/stack.py @@ -0,0 +1,32 @@ +from typing import Generic, TypeVar + +T = TypeVar('T') + + +class Stack(Generic[T]): + def __init__(self): + self.top: int = 0 + self.data: list[T] = [] + + def push(self, value: T): + self.data.append(value) + self.top += 1 + + def pop(self) -> T | None: + if self.top > 0: + self.top -= 1 + return self.data.pop() + else: + return None + + def peek(self) -> T | None: + if self.top > 0: + return self.data[self.top - 1] + else: + return None + + def is_empty(self) -> bool: + return self.top == 0 + + def size(self) -> int: + return self.top diff --git a/test/__pycache__/test_stack.cpython-311-pytest-7.4.3.pyc b/test/__pycache__/test_stack.cpython-311-pytest-7.4.3.pyc new file mode 100644 index 0000000..9d2f95b Binary files /dev/null and b/test/__pycache__/test_stack.cpython-311-pytest-7.4.3.pyc differ diff --git a/test/test_stack.py b/test/test_stack.py new file mode 100644 index 0000000..0a29bc8 --- /dev/null +++ b/test/test_stack.py @@ -0,0 +1,58 @@ +from stack.parentheses import par_match +from stack.number_conversion import decimal_to_any +from stack.infix_conversion import infix_to_prefix, infix_to_postfix + + +def test_par_match1(): + parentheses = '((()))(()()' + assert not par_match(parentheses) + + +def test_par_match2(): + parentheses = '((()))(())' + assert par_match(parentheses) + + +def test_par_match3(): + parentheses = '(((5+3)))*((4-2))' + assert par_match(parentheses) + + +def test_to_binary1(): + num = 5 + assert decimal_to_any(num, 2) == '101' + + +def test_to_binary2(): + num = 10 + assert decimal_to_any(num, 2) == '1010' + + +def test_infix_to_prefix(): + infix = 'a+b*c' + assert infix_to_prefix(infix) == '+a*bc' + + +def test_infix_to_prefix_with_parentheses1(): + infix = '(a+b)*c' + assert infix_to_prefix(infix) == '*+abc' + + +def test_infix_to_prefix_with_parentheses2(): + infix = '(a+b)*(c-d)' + assert infix_to_prefix(infix) == '*+ab-cd' + + +def test_infix_to_postfix(): + infix = 'a+b*c' + assert infix_to_postfix(infix) == 'abc*+' + + +def test_infix_to_postfix_with_parentheses1(): + infix = '(a+b)*c' + assert infix_to_postfix(infix) == 'ab+c*' + + +def test_infix_to_postfix_with_parentheses2(): + infix = '(a+b)/(c-d)' + assert infix_to_postfix(infix) == 'ab+cd-/' \ No newline at end of file