数据结构+算法
Stack() 创建一个空的新栈。 它不需要参数,并返回一个空栈。
push(item)将一个新项添加到栈的顶部。它需要 item 做参数并不返回任何内容。
pop() 从栈中删除顶部项。它不需要参数并返回 item 。栈被修改。
peek() 从栈返回顶部项,但不会删除它。不需要参数。 不修改栈。
isEmpty() 测试栈是否为空。不需要参数,并返回布尔值。
size() 返回栈中的 item 数量。不需要参数,并返回一个整数。
class Stack(): def __init__(self): self.items = [] def push(self,item): self.items.append(item) def pop(self): if self.isEmpty(): return '空' else: return self.items.pop() def isEmpty(self): #空=》True return self.items == [] def peek(self): return self.items[len(self.items) - 1] def size(self): return len(self.items)
Queue() 创建一个空的新队列。 它不需要参数,并返回一个空队列。
enqueue(item) 将新项添加到队尾。 它需要 item 作为参数,并不返回任何内容。
isEmpty() 查看队列是否为空。它不需要参数,并返回布尔值。
class Queue(): def __init__(self): self.items = [] def enqueue(self,item): self.items.insert(0,item) def isEmpty(self): return self.items == [] def dequeue(self): if self.isEmpty(): return '空' else: return self.items.pop() def size(self): return len(self.items) def travel(self): print(self.items)
Deque() 创建一个空的新 deque。它不需要参数,并返回空的 deque。
addFront(item) 将一个新项添加到 deque 的首部。它需要 item 参数 并不返回任何内容。
addRear(item) 将一个新项添加到 deque 的尾部。它需要 item 参数并不返回任何内容。
removeFront() 从 deque 中删除首项。它不需要参数并返回 item。deque 被修改。
removeRear() 从 deque 中删除尾项。它不需要参数并返回 item。deque 被修改。
isEmpty() 测试 deque 是否为空。它不需要参数,并返回布尔值。
class Dequeue(): def __init__(self): self.items = [] def addFont(self,item): self.items.append(item) def addRear(self,item): self.items.insert(0,item) def isEmpty(self): return self.items == [] def removeFont(self): if self.isEmpty(): return None else: return self.items.pop() def removeRear(self): if self.isEmpty(): return None else: return self.items.pop(0) def size(self): return len(self.items)
应用:判断是否是回文
def isHuiWei(s): #将字符添加到双端队列中 q = Dequeue() #表示字符串是否为回文 for ch in s: q.addFont(ch) while q.size() > 1: first = q.removeFont() last = q.removeRear() if first != last: return False return True
- 集合中存储的元素是有顺序的,顺序表的结构可以分为两种形式:单数据类型和多数据类型。
- python中的列表和元组就属于多数据类型的顺序表
- 单数据类型顺序表的内存图(内存连续开启)
- 对应的内存空间是连续开辟的
- 顺序表的变量/引用存的的(指向的)是内存空间的首地址
- 多数据类型顺序表的内存图(内存非连续开辟)
链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是不像顺序表一样连续存储数据,而是每一个结点(数据存储单元)里存放下一个结点的信息(即地址)
. is_empty():链表是否为空
. length():链表长度
. travel():遍历整个链表
. add(item):链表头部添加元素
. append(item):链表尾部添加元素
. insert(pos, item):指定位置添加元素
. remove(item):删除节点
. search(item):查找节点是否存在
#定义节点类 class Node(): def __init__(self,item): self.item = item self.next = None def __str__(self): return self.item #封装链表数据结构 class Link(): #初始化一个空链表 def __init__(self): #该属性永远指向第一个节点 self._head = None def isEmpty(self): return self._head == None def add(self,item): #创建一个新的节点对象 node = Node(item) #将节点插入到链表的头部 node.next = self._head self._head = node def travel(self): cur = self._head while cur: print(cur.item) cur = cur.next def length(self): count = 0 cur = self._head while cur: count += 1 cur = cur.next return count def append(self,item): cur = self._head pre = None #cur前面节点的地址 node = Node(item) #如果链表为空则新节点作为链表中的第一个节点 if self._head is None: self._head = node return #链表非空对应的插入情况 while cur: pre = cur cur = cur.next pre.next = node def insert(self,pos,item): cur = self._head pre = None node = Node(item) length = self.length() #对特殊情况的处理 if pos > length: self.append(item) return if pos <= 0: self.add(item) return #正常处理 for i in range(pos): pre = cur cur = cur.next pre.next = node node.next = cur def remove(self,item): cur = self._head pre = None #如果删除的是第一个节点 if item == cur.item: self._head = cur.next return while cur: if cur.item == item: pre.next = cur.next return else: pre = cur cur = cur.next def search(self,item): find = False cur = self._head while cur: if cur.item == item: find = True break cur = cur.next return find
左叶子节点
右叶子节点
二叉树的遍历 广度遍历(层级): 深度遍历: 前序(根左右): 中序(左根右): 后序(左右根)
二叉树的增加与遍历
class Node(): def __init__(self,item): self.item = item self.left = None self.right = None class Tree(): def __init__(self): self.root = None def add(self,item): node = Node(item) if self.root is None: self.root = node return queue = [self.root] while queue: cur = queue.pop(0) if cur.left is None: cur.left = node return else: queue.append(cur.left) if cur.right is None: cur.right = node return else: queue.append(cur.right) def travel(self): if self.root is None: return queue = [self.root] while queue: cur = queue.pop(0) print(cur.item) if cur.left is not None: queue.append(cur.left) if cur.right is not None: queue.append(cur.right)
class Node(): def __init__(self,item): self.item = item self.left = None self.right = None class Tree(): def __init__(self): self.root = None def insertByOder(self,item): node = Node(item) if self.root is None: self.root = node return cur = self.root while True: if item < cur.item: if cur.left is None: cur.left = node return else: cur = cur.left else: if cur.right is None: cur.right = node return else: cur = cur.right def forward(self,root): if root is None: return # 根 左 右 print(root.item,end=' ') self.forward(root.left) self.forward(root.right) def mid(self,root): if root is None: return #左根右 self.mid(root.left) print(root.item,end=' ') self.mid(root.right) def back(self,root): if root is None: return #左右根 self.back(root.left) self.back(root.right) print(root.item,end=' ')
#递归版本 def CountNode(self, root): if root == None: return 0 return self.CountNode(root.left) + self.CountNode(root.right) + 1 #非递归版本 def CountNodeNotRev(self, root): if root == None: return 0 stack = [] stack.append(root) index = 0 while index<len(stack): if stack[index].left: stack.append(stack[index].left) if stack[index].right: stack.append(stack[index].right) index += 1 print(len(stack)) output: 11
def getTreeDepth(self, root): if root == None: return 0 left = self.getTreeDepth(root.left) + 1 right = self.getTreeDepth(root.right) + 1 return left if left>right else right
def countLeaves(self, root): if root == None: return 0 if root.left==None and root.right==None: return 1 return self.countLeaves(root.left)+self.countLeaves(root.right)
def getKLevel(self, root, K): if root == None: return 0 if K == 1: return 1 return self.getKLevel(root.left, K-1)+self.getKLevel(root.right, K-1)
def StrucCmp(self, root1, root2): if root1 == None and root2 == None: return True elif root1 ==None or root2 == None: return False return self.StrucCmp(root1.left, root2.left) and self.StrucCmp(root1.right, root2.right)
def Mirror(self, root): if root == None: return tmp = root.left root.left = root.right root.right = tmp self.Mirror(root.left) self.Mirror(root.right)
- 当数据存储在诸如列表的集合中时,我们说这些数据具有线性或顺序关系。 每个数据元素都存储在相对于其他数据元素的位置。 由于这些索引值是有序的,我们可以按顺序访问它们。 这个过程产实现的搜索即为顺序查找。
- 顺序查找原理剖析:
- 从列表中的第一个元素开始,我们按照基本的顺序排序,简单地从一个元素移动到另一个元素,直到找到我们正在寻找的元素或遍历完整个列表。如果我们遍历完整个列表,则说明正在搜索的元素不存在。
- 代码实现:该函数需要一个列表和我们正在寻找的元素作为参数,并返回一个是否存在的布尔值。found 布尔变量初始化为 False,如果我们发现列表中的元素,则赋值为 True。
def search(alist,item): find = False cur = 0 while cur < len(alist): if alist[cur] == item: find = True break else: cur += 1 return find
有序列表对于我们的实现搜索是很有用的。在顺序查找中,当我们与第一个元素进行比较时,如果第一个元素不是我们要查找的,则最多还有 n-1 个元素需要进行比较。 二分查找则是从中间元素开始,而不是按顺序查找列表。 如果该元素是我们正在寻找的元素,我们就完成了查找。 如果它不是,我们可以使用列表的有序性质来消除剩余元素的一半。如果我们正在查找的元素大于中间元素,就可以消除中间元素以及比中间元素小的一半元素。如果该元素在列表中,肯定在大的那半部分。然后我们可以用大的半部分重复该过程,继续从中间元素开始,将其与我们正在寻找的内容进行比较。
def search(alist,item):
if alist and alist[-1]==item:
return True left = 0 right = len(alist)-1 find = False
while left < right: #列表中间元素的索引 mid_index = left+(right-left) // 2 if item == alist[mid_index]: find = True break else: if item > alist[mid_index]: left = mid_index + 1 else: right = mid_index - 1 return find
def sort(alist): length = len(alist) for j in range(0,length-1): for i in range(0,length-1-j): if alist[i] > alist[i+1]: alist[i],alist[i+1] = alist[i+1],alist[i]
def sort(alist): length = len(alist) for j in range(length-1,0,-1): #最大值元素的下标 max_index = 0 for i in range(1,j+1): if alist[max_index] < alist[i]: max_index = i alist[max_index],alist[j] = alist[j],alist[max_index]
def sort(alist): length = len(alist) for j in range(1,length): i = j # i就是无序列表中的第一个元素 while i > 0: if alist[i] < alist[i-1]: alist[i],alist[i-1] = alist[i-1],alist[i] i -= 1 else: break
def sort(alist): gap = len(alist) // 2 while gap >= 1: for j in range(gap,len(alist)): i = j while i > 0: if alist[i] < alist[i-gap]: alist[i],alist[i-gap] = alist[i-gap],alist[i] i -= gap else: break gap = gap // 2
-
从数列中挑出一个元素,称为 "基准"(pivot);
-
重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
-
递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;
def sort(alist,start,end): low = start high = end if low >= high: return mid = alist[low] while low < high: while low < high: if alist[high] >= mid: high -= 1 else: alist[low] = alist[high] break while low < high: if alist[low] < mid: low += 1 else: alist[high] = alist[low] break alist[low] = mid #### #在mid左侧列表中递归调用该函数 sort(alist,start,low-1) #mid右侧 sort(alist,high+1,end)
def quickSort(arr, left=None, right=None): left = 0 if not isinstance(left,(int, float)) else left right = len(arr)-1 if not isinstance(right,(int, float)) else right if left < right: partitionIndex = partition(arr, left, right) quickSort(arr, left, partitionIndex-1) quickSort(arr, partitionIndex+1, right) return arr def partition(arr, left, right): pivot = left index = pivot+1 i = index while i <= right: if arr[i] < arr[pivot]: swap(arr, i, index) index+=1 i+=1 swap(arr,pivot,index-1) return index-1 def swap(arr, i, j): arr[i], arr[j] = arr[j], arr[i]
作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法:
- 自上而下的递归(所有递归的方法都可以用迭代重写,所以就有了第 2 种方法);
- 自下而上的迭代;
算法步骤
-
申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
-
设定两个指针,最初位置分别为两个已经排序序列的起始位置;
-
比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
-
重复步骤 3 直到某一指针达到序列尾;
-
将另一序列剩下的所有元素直接复制到合并序列尾。
def mergeSort(arr): import math if(len(arr)<2): return arr middle = math.floor(len(arr)/2) left, right = arr[0:middle], arr[middle:] return merge(mergeSort(left), mergeSort(right)) def merge(left,right): result = [] while left and right: if left[0] <= right[0]: result.append(left.pop(0)) else: result.append(right.pop(0)); while left: result.append(left.pop(0)) while right: result.append(right.pop(0)); return result