数据结构+算法

队列

双端队列

顺序表

链表

二叉树

  增加和遍历

  前序、中序、后序遍历

  总节点数

  树的深度

  叶子节点数

  K层节点数

  树是否相同

  树镜像

查找算法

  顺序查找

  二分查找

排序算法

  冒泡排序

  选择排序

  插入排序

  希尔排序(缩小增量排序)

  快排(快速排序)

  归并排序

python中的散列表

 

一、栈

先进后出(如浏览器中的前进后退按钮、递归函数)

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 作为参数,并不返回任何内容。

dequeue() 从队首移除项。它不需要参数并返回 item。 队列被修改。

isEmpty() 查看队列是否为空。它不需要参数,并返回布尔值。

size() 返回队列中的项数。它不需要参数,并返回一个整数。

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 是否为空。它不需要参数,并返回布尔值。

size() 返回 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)

获取第K层节点数

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)

七、查找算法

1.顺序查找

 

  • 当数据存储在诸如列表的集合中时,我们说这些数据具有线性或顺序关系。 每个数据元素都存储在相对于其他数据元素的位置。 由于这些索引值是有序的,我们可以按顺序访问它们。 这个过程产实现的搜索即为顺序查找。
  • 顺序查找原理剖析:
    • 从列表中的第一个元素开始,我们按照基本的顺序排序,简单地从一个元素移动到另一个元素,直到找到我们正在寻找的元素或遍历完整个列表。如果我们遍历完整个列表,则说明正在搜索的元素不存在。
  • 代码实现:该函数需要一个列表和我们正在寻找的元素作为参数,并返回一个是否存在的布尔值。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

2.二分查找

有序列表对于我们的实现搜索是很有用的。在顺序查找中,当我们与第一个元素进行比较时,如果第一个元素不是我们要查找的,则最多还有 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

八、排序算法

1.冒泡排序

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]

 

2.选择排序

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]

3.插入排序

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

 

4.希尔排序(缩小增量排序)

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

 

5.快排(快速排序)

 

  1. 从数列中挑出一个元素,称为 "基准"(pivot);

  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;

  3. 递归地(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 种方法);
  • 自下而上的迭代;

算法步骤

  1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;

  2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置;

  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;

  4. 重复步骤 3 直到某一指针达到序列尾;

  5. 将另一序列剩下的所有元素直接复制到合并序列尾。

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

 

posted @ 2019-06-02 11:54  海予心  阅读(426)  评论(0编辑  收藏  举报