CTF(鶸)密码学

Python Algorithm CTF(鶸)密码学 一、摩斯密码 1、特点 题面只有三个值。 2、解题思路 转换成 ascii,出现 flag 标识符即结束,否则根据转后的数据进行下一步处理。 二、栅栏密码 1、特点 密文字符串出间隔性的出现 flag 的标识符。 2、解题思路 分栏破译。 def inputData(): string = input("请输入栅栏加密的文字:") code = input("请输入分栏:(0代表从2到6逐个分栏):") code = int(code) return string,code def code2(string): string_temp = [] string_temp.append(string[0::2]) string_temp.append(string[1::2]) print("分成2栏的结果是:%s" % (''.join(string_temp))) def code3(string): string_temp = [] string_temp.append(string[0::3]) string_temp.append(string[1::3]) string_temp.append(string[2::3]) print("分成3栏的结果是:%s" % (''.join(string_temp))) def code4(string): string_temp = [] string_temp.append(string[0::4]) string_temp.append(string[1::4]) string_temp.append(string[2::4]) string_temp.append(string[3::4]) print("分成4栏的结果是:%s" % (''.join(string_temp))) def code5(string): string_temp = [] string_temp.append(string[0::5]) string_temp.append(string[1::5]) string_temp.append(string[2::5]) string_temp.append(string[3::5]) string_temp.append(string[4::5]) print("分成5栏的结果是:%s" % (''.join(string_temp))) def code6(string): string_temp = [] string_temp.append(string[0::6]) string_temp.append(string[1::6]) string_temp.append(string[2::6]) string_temp.append(string[3::6]) string_temp.append(string[4::6]) string_temp.append(string[5::6]) print("分成6栏的结果是:%s" % (''.join(string_temp))) def main(): string, code = inputData() if (code == 0): code2(string) code3(string) code4(string) code5(string) code6(string) elif (code == 2): code2(string) elif (code == 3): code3(string) elif (code == 4): code4(string) elif (code == 5): code4(string) elif (code == 6): code4(string) else: print("error") if __name__ == "__main__": main() 三、Rot13 1、特点 凯撒加密的第十二种方式,但是可以字符和数字混合在其中。 ...

单链表的Python实现(列表实现)

Python Data Structure 单链表的 Python 实现 一、节点 节点,即 C 语言里使用 struct 语句定义的一种非基础数据类型,在 Python 中,定义一个class 类。 class Node(object): def __init__(self, data, next=None): """包含一个数据域,一个 next 域的节点,next 是对下一个数据的引用 """ self.data = data self.next = next class TwoWayNode(Node): """继承 Node 类的双指针节点类,新包含一个 previous 的引用 """ def __init__(self, data, previous=None, next=None): Node.__init__(self, data, next) self.previous = previous def main(): pass if __name__ == "__main__": main() 二、单链表 单链表,指的是由多个节点形成的链式结构,一个节点包括一个数据域及一个 next 域。 除头结点外,每个节点都有且仅有一个前驱;除尾节点外,每个节点有且仅有一个后继。 ADT 思想(忽略)。 定义一个单链表类,依次给出以下的方法: 1、 在首部插入节点 2、在尾部插入节点 3、在任意位置插入节点 4、从首部删除节点 5、从尾部删除节点 6、从任意位置删除节点 7、遍历输出 8、根据数值查找单链表中是否存在项,返回 True or False 及索引位置 9、根据给出的索引替换掉相应位置的值 from node import Node class SingleList(object): """以节点的方式实现链表,默认实现空列表 """ def __init__(self): self.head = None # 在开始处插入 def add_node_first(self, data): self.head = Node(data, self.head) # 在末尾插入,若为空列表则直接插入,否则遍历到尾部 def add_node_last(self, data): new_node = Node(data) if self.head is None: self.head = new_node else: probe = self.head while probe.next is not None: probe = probe.next probe.next = new_node # 任意位置添加节点,若 index 小于零,加在首部,若 index 大于链表长度,加在尾部 def add_node_anywhere(self, index, data): if self.head is None or index <= 0: self.head = Node(data, self.head) else: probe = self.head while index >1 and probe.next is not None: probe = probe.next index -= 1 probe.next = Node(data, probe.next) # 从首部删除节点 def pop_node_first(self): if self.head is not None: removed_item = self.head.data self.head = self.head.next return removed_item else: return -1 # 从尾部删除节点 def pop_node_last(self): if self.head is None: return -1 elif self.head.next is None: removed_item = self.head.data self.head = None else: probe = self.head while probe.next.next is not None: probe = probe.next removed_item = probe.next.data probe.next = None return removed_item # 任意位置删除节点,若 index 小于零,则删除首部节点,若 index 大于链表长度,则删除尾部节点 def pop_node_anywhere(self, index): if index <= 0 or self.head.next is None: removed_item = self.head.data self.head = self.head.next return removed_item else: probe = self.head while index > 1 and probe.next.next is not None: probe = probe.next index -= 1 removed_item = probe.next.data probe.next = probe.next.next return removed_item # 遍历输出 def traverse(self): probe = self.head while probe is not None: print(probe.data) probe = probe.next # 根据数值查找链表有没有该数据 def search(self, data): probe = self.head cnt = 0 while probe is not None and data != probe.data: probe = probe.next cnt += 1 if probe is not None: return "In", cnt else: return "Not in", -1 # 根据索引位置替换数据 def replace(self, index, new_data): probe = self.head while index > 0 and probe is not None: probe = probe.next index -= 1 if probe is None: return -1 else: probe.data = new_data return "Done" # 测试用例 a = SingleList() a.add_node_first(1) a.add_node_first(2) a.add_node_first(3) print(a.search(2)) a.add_node_first(4) a.add_node_last(5) a.add_node_first(6) a.add_node_anywhere(100,33) a.pop_node_anywhere(2) a.traverse() print("--------")

常见排序算法的 Python 实现

Python [[Algorithm]] 常见排序算法的 Python 实现 选择排序 """ 选择排序,顾名思义,扫描全表,选最小值 外循环走size-1次,每一次确定当前一个最小的数 内循环走size-(已经确定的最小数),理解为当前位置之前的数字都已有序,从当前位置出发到结尾扫描确定当前最小的数字 时间复杂度:平均O(n**2),最坏O(n**2),最好O(n**2) 空间复杂度:O(1) 稳定性:不稳定 """ def select_sort(sort_list): for i in range(size-1): min = i for j in range(i, size): if sort_list[j] < sort_list[min]: min = j sort_list[min], sort_list[i] = sort_list[i], sort_list[min] print("选择排序结果是:",sort_list) 冒泡排序 """ 冒泡排序,逐个比较,将最大的数排到最后方 外循环走size-1次,每次确定一个最大的数 内循环走size-(当前已确定的数),理解为从头开始,两两比较,a(n)>a(n+1),则交换 时间复杂度:平均O(n**2),最坏O(n**2),最好O(n) 空间复杂度:O(1) 稳定性:稳定 """ def bub_sort(sort_list): for i in range(size-1): for j in range(1, size): if sort_list[j] < sort_list[j-1]: sort_list[j], sort_list[j-1] = sort_list[j-1], sort_list[j] print("冒泡排序结果是:",sort_list) 插入排序 """ 插入排序,类似于体育课排队列 外循环走size-1次,每次确定一个较小的数,一次内循环结束,当前位置的左侧是相对大小确定的 内循环走0次或者当前已确定数的次数,理解为当前数与之前的第一个数对比,若小于则交换,继而继续比较,所以最少0次,最多当前已确定数次 时间复杂度:平均O(n**2),最坏O(n**2),最好O(n) 空间复杂度:O(1) 稳定性:稳定 """ def insert_sort(sort_list): for i in range(1, size): j = i while j > 0 and sort_list[j]<sort_list[j-1]: sort_list[j], sort_list[j-1] = sort_list[j-1], sort_list[j] j -= 1 print("插入排序结果是:",sort_list) 希尔排序 """ 希尔排序(该处指配合插入排序的希尔排序),由插入排序的定义可以看出来,当前的数想要确定位置必须与之前的数字逐个比较, 而希尔排序改成h个比较,这样做的好处是,针对数据量大的数组,排序的过程更轻松(构建h个不同的子数组,每个子数组逻辑相邻(相差距离为h)) 外循环的运算次数为(size = size//3循环,直到size等于1,每循环一次,运算次数加一 如size = 150,150//3=50(1次),50//3=16(2次),16//3=5(3次),5//3=1(4次)) 内循环为选择插入排序,次数由当前的外循环变量决定 时间复杂度:平均O(n**1.3),其他情况不好分析 空间复杂度:O(1) 稳定性:不稳定 """ def shell_sort(sort_list): h = 1 while h < size//3: h = h*3+1 while h >=1: for i in range(h, size): j = i while j > h and sort_list[j]<sort_list[j-h]: sort_list[j], sort_list[j-h] = sort_list[j-h], sort_list[j] j -= h h = h//3 print("希尔排序结果是:",sort_list) 归并排序 """ 归并排序,分治算法思想,将一个大问题分解成若干个小问题,若问题类似可用递归完成 常见两种归并算法,自顶向下和自底向上 自顶向下的算法用递归的方法,先解决左边的排序,再解决右边的排序 自底向上的算法用拆解合并的思想,先拆成size/2个小数组进行归并排序,继而将结果拆成size/4个数组归并排序,当size/(2**n)<1时完成排序 时间复杂度:平均O(nlog2n),最坏O(nlog2n),最好O(nlog2n) 空间复杂度:O(n)(需要一个临时数组来保存) 稳定性:稳定 """ class merge(object): #原地归并抽象方法,方便复用,传入数组,左值,中值,右值 def merge_sort(self, sort_list, lo, mid, hi): i = lo j = mid+1 aux = copy.deepcopy(sort_list) for k in range(lo, hi+1): if i > mid: sort_list[k] = aux[j] j += 1 elif j > hi: sort_list[k] = aux[i] i += 1 elif aux[j] <= aux[i]: sort_list[k] = aux[j] j += 1 else: sort_list[k] = aux[i] i += 1 def sort(self, sort_list): self.sort1(sort_list, 0, size-1) #自顶向下的归并排序 def sort1(self, sort_list, lo, hi): if hi <= lo: return sort_list mid = lo + (hi-lo)//2 self.sort1(sort_list, lo, mid) self.sort1(sort_list, mid+1, hi) self.merge_sort(sort_list, lo, mid, hi) def sort2(self, sort_list): sz = 1 while sz < size: lo = 0 while lo < size-sz: self.merge_sort(sort_list, lo, lo+sz-1, min(lo+sz+sz-1, size-1)) lo += sz+sz sz = sz+sz print(sort_list) 快速排序 """ 快速排序,是常规条件下最快的排序算法,使用分治算法思想,利用递归完成 首先先改变数组内部顺序(消除输入依赖),然后通过切分函数找出一个值(二分切分中,该值越接近正确顺序的中值越好) 以该值为mid,递归调用自身,分而治之 重点在于切分函数,二分切分函数的思想是,以某子数组第一个数a为基准, 从左往右扫描找出一个大于a的数,再从右往左扫描找出一个小于a的数,两者交换 最后将a放到正确的位置,返回切分的数的索引 时间复杂度:平均O(nlog2n),最坏O(n**2),最好O(nlog2n) 空间复杂度:O(log2n)(需要一个临时数组来保存) 稳定性:不稳定 """ class quick(object): #消除输入依赖 def sort(self, sort_list): random.sample(sort_list, size) self.sort1(sort_list, 0, size-1) #递归主函数体,从切分函数得到切分索引,左右递归,递归结束不用归并 def sort1(self, sort_list, lo, hi): if hi <= lo: return sort_list j = self.partition(sort_list, lo, hi) self.sort1(sort_list, lo, j-1) self.sort1(sort_list, j+1, hi) #切分函数,左右指针,轮流扫描,交换位置,最后将切分元素放到正确的位置,返回切分索引 def partition(self, sort_list, lo, hi): i = lo j = hi+1 v = sort_list[lo] while True: i = i + 1 while sort_list[i]<v: if i==hi: break i += 1 j = j - 1 while v < sort_list[j]: if j==lo: break j -= 1 if i >= j: break sort_list[i], sort_list[j] = sort_list[j], sort_list[i] sort_list[lo], sort_list[j] = sort_list[j], sort_list[lo] return j 基数排序 """ 基数排序,不进行比较的整数排序算法,基数指的是整数的进制(默认为10), 根据位数要做几次不同的桶排序,位数的计算为int(math.ceil(math.log(max(sort_list)+1, radix))) 每次循环完成当前位数(个位、十位、百位)的大小排序,理解过程可见http://bubkoo.com/2014/01/15/sort-algorithm/radix-sort/ 一共有十个桶,分别对应0-10,每个桶有若干数据,则桶可以用二维数组完成,记为a[index1][index2], 对每一个sort_list里的数,index1 = sort_list_num%(radix**i)//(radix**(i-1)) 时间复杂度:平均O(k*n),最坏O(k*n),最好O(k*n),k为最大数字的位数 空间复杂度:O(n) 稳定性:稳定 """ def radix_sort(sort_list, radix=10): """sort_list为整数列表, radix为基数""" K = int(math.ceil(math.log(max(sort_list)+1, radix))) for i in range(1, K+1): bucket = [[] for i in range(radix)] for val in sort_list: bucket[val%(radix**i)//(radix**(i-1))].append(val) del sort_list[:] for each in bucket: sort_list.extend(each) print(sort_list) 测试 import copy import random import math sort_list = [20,1,24,54,11,26,87,45,32,544,25,87,47,48,58,1024] global size size = len(sort_list) #select_sort(sort_list) #bub_sort(sort_list) #insert_sort(sort_list) #shell_sort(sort_list) #自顶向下归并排序测试 # a = merge() # a.sort(sort_list) # print(sort_list) #自底向上归并排序测试 # a = merge() # a.sort2(sort_list) # print(sort_list) #快速排序测试 # print(sort_list) # a = quick() # a.sort(sort_list) # print(sort_list) #基数排序测试 #radix_sort(sort_list)

栈的 Python 实现(列表)

Python [[Data Structure]] 栈的 Python 实现(列表) class Stack(object): """栈的 Python 列表实现 """ # 初始化对象,生成空列表 def __init__(self): self.item = [] # 判断栈是否为空,返回 True or False def isEmpty(self): return self.item == [] # 入栈方法,添加至列表尾部 def push(self, item): self.item.append(item) # 出栈方法,从队列尾部弹出,并返回弹出值 def pop(self): return self.item.pop() # 查栈顶元素方法,返回栈顶元素值,但不弹出 def peek(self): return self.item[len(self.item)-1] # 查看栈的大小方法,返回 int 值 def size(self): return len(self.item) def match_sympol(string): """ 利用栈的特性(后进先出),对三种常见括号进行匹配 对于左括号,直接压入栈,遇到右括号,弹出栈顶元素,若能一一对应,且最终栈为空,则完全匹配 """ s = Stack() flag = True index = 0 while index < len(string) and flag: symbol = string[index] if symbol in "({[": s.push(symbol) else: if s.isEmpty(): flag = False else: top = s.pop() if not matches_help(top, symbol): flag = False index += 1 if flag and s.isEmpty(): return True else: return False def matches_help(open, close): """ 匹配辅助函数 传入两个 char 参数,判断是否对应,返回 True or False """ opens = "({[" closes = ")}]" return opens.index(open) == closes.index(close) def ten2two(num): """ 十进制转二进制,原理是除二取余法 将十进制数除二取余数,将余数压入栈,直到十进制数为 0,然后栈逐个弹出 """ s = Stack() while num > 0: rem = num%2 s.push(rem) num = num//2 binString = "" while not s.isEmpty(): binString = binString + str(s.pop()) return binString def infixToPostfix(infixexpr): """ 中序表达式转后续表达式 中序表达式转换后续表达式有个简单的方法,先将中序表达式的每一次运算都加上括号,接着从右往左, 找到第一个算数符号替换掉最近的右括号,并将对应的左括号去除,继续往左执行,直到没有括号为止 具体过程: 1、创建一个名为 opstack 的空栈以保存运算符。给输出创建一个空列表。 2、通过使用字符串方法拆分将输入的中缀字符串转换为标记列表。 3、从左到右扫描标记列表。 如果标记是操作数,将其附加到输出列表的末尾。 如果标记是左括号,将其压到 opstack 上。 如果标记是右括号,则弹出 opstack,直到删除相应的左括号。将每个运算符附加到输出列表的末尾。 如果标记是运算符,*,/,+或 - ,将其压入 opstack。但是,首先删除已经在 opstack 中具有更高或相等优先级的任何运算符,并将它们加到输出列表中。 4、当输入表达式被完全处理时,检查 opstack。仍然在栈上的任何运算符都可以删除并加到输出列表的末尾。 理解过程可见:https://facert.gitbooks.io/python-data-structure-cn/3.%E5%9F%BA%E6%9C%AC%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/3.9.%E4%B8%AD%E7%BC%80%E5%89%8D%E7%BC%80%E5%92%8C%E5%90%8E%E7%BC%80%E8%A1%A8%E8%BE%BE%E5%BC%8F/ """ prec = {} prec["*"] = 3 prec["/"] = 3 prec["+"] = 2 prec["-"] = 2 prec["("] = 1 opStack = Stack() postfixList = [] tokenList = infixexpr.split() for token in tokenList: if token in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" or token in "0123456789": postfixList.append(token) elif token == '(': opStack.push(token) elif token == ')': topToken = opStack.pop() while topToken != '(': postfixList.append(topToken) topToken = opStack.pop() else: while (not opStack.isEmpty()) and (prec[opStack.peek()] >= prec[token]): postfixList.append(opStack.pop()) opStack.push(token) while not opStack.isEmpty(): postfixList.append(opStack.pop()) return " ".join(postfixList) def postfixEval(postfixExpr): """ 后缀表达式的算值 根据后缀表达式的特点,很容易可以想到,将运算数压入栈,当出现符号时,弹出栈顶两个元素,计算完成后压入栈, 等待下一个运算数或者运算符,最后栈顶元素就是后缀表达式的值。 """ operandStack = Stack() tokenList = postfixExpr.split() for token in tokenList: if token in "0123456789": operandStack.push(int(token)) else: operand2 = operandStack.pop() operand1 = operandStack.pop() result = doMath(token, operand1, operand2) operandStack.push(result) return operandStack.pop() def doMath(op, op1, op2): """ 后缀表达式运算值的辅助函数 输入三个参数(运算符,操作数1,操作数2),返回运算结果。 """ if op == "*": return op1 * op2 elif op == "/": return op1 / op2 elif op == "+": return op1 + op2 else: return op1 - op2 #栈的测试 # s= Stack() # print(s.isEmpty()) # s.push(4) # s.push('dog') # print(s.peek()) # s.push(True) # print(s.size()) # print(s.isEmpty()) # s.push(8.4) # print(s.pop()) # print(s.pop()) # print(s.size()) # 符号匹配的测试 # print(match_sympol('')) # 十进制数转二进制的测试 # print(ten2two(100)) # 中缀表达式转后缀表达式的测试 # print(infixToPostfix("( A + B ) * C - ( D - E ) * ( F + G )")) # 后缀表达式的求求值 # print(postfixEval('7 8 + 3 2 + /'))

队列的Python实现(列表实现)

Python Data Structure 队列的 Python 实现(列表实现) class Queue(object): """队列的定义 """ # 队列的初始化,生成空列表 def __init__(self): self.item = [] # 队列判空方法,返回 True or False def isEmpty(self): return self.item == [] # 求队列元素个数方法,返回 int 值 def size(self): return len(self.item) # 入队列方法,从列表头部插入 def enqueue(self, value): self.item.insert(0, value) # 出队列方法,从列表尾部弹出,返回弹出值 def dequeue(self): return self.item.pop() def hotpotato(namelist, num): """ 利用队列,完成烫手山芋算法(类似于点兵出列) 先填充满队列,然后做 num 次循环,每次循环将列首出列,再入列,直到最后一个数据直接出列 当队列的元素只剩一个时,就是最后的 winner """ simqueue = Queue() for name in namelist: simqueue.enqueue(name) while simqueue.size() > 1: for i in range(num): simqueue.enqueue(simqueue.dequeue()) simqueue.dequeue() return simqueue.dequeue() # 队列测试 # q = Queue() # print(q.size(), "\n", q.isEmpty(), "\n", q.enqueue(2), "\n",\ # q.enqueue("dog"), "\n", q.dequeue(), "\n", q.size(), "\n", q.dequeue()) # 烫手山芋测试 # print(hotpotato(["Bill","David","Susan","Jane","Kent","Brad"],7))