数据结构

 数据结构基础

 
数据结构

  定义:简单来说,数据结构就是设计数据以何种方式组织并存储在计算机中。比如:列表、集合与字典等都是一种数据结构。

  PS:“程序=数据结构+算法”

  列表:在其他编程语言中称为“数组”,是一种基本的数据结构类型。
    关于:列表的存储问题!
数据结构的分类:
  线性结构:数据结构中的元素存在一对一的相互关系
  树结构:数据结构中的元素存在一对多的相互关系
  图结构:数据结构中的元素存在多对多的相互关系
栈:   栈(Stack)是一个数据集合,可以理解为只能在一端进行插入或删除操作的列表。   栈的特点:后进先出(last
-in, first-out)   栈的概念:     栈顶     栈底   栈的基本操作:     进栈(压栈):push     出栈:pop     取栈顶:gettop
复制代码

复制代码
#利用python简单的实现栈操作
class
Stack(object): def __init__(self): self.stack=[] def isEmpty(self): return self.stack==[] def push(self,item): self.stack.append(item) def pop(self): if self.isEmpty(): raise IndexError,'pop from empty stack' return self.stack.pop() def peek(self): return self.stack[-1] def size(self): return len(self.stack)
复制代码
复制代码
栈的应用——括号匹配问题
括号匹配问题:给一个字符串,其中包含小括号、中括号、大括号,求该字符串中的括号是否匹配。
例如:
  ()()[]{}    匹配
  ([{()}])    匹配
  [](    不匹配
  [(])    不匹配
复制代码
复制代码
def Matching(exp="{[()]}"):
    stack = []
    for i in exp:
        if i in {'(','[','{'}:
            stack.append(i)
        if i == ')':
            if len(stack)>0 and stack[-1] == '(':
                stack.pop()
            else:
                return False
        if i == ']':
            if len(stack)>0 and stack[-1] == '[':
                stack.pop()
            else:
                return False
        if i == '}':
            if len(stack)>0 and stack[-1] == '{':
                stack.pop()
            else:
                return False
    if len(stack)==0:
        return True
    else:
        return False
复制代码
复制代码
队列
  队列(Queue)是一个数据集合,仅允许在列表的一端进行插入,另一端进行删除。
    进行插入的一端称为队尾(rear),插入动作称为进队或入队
    进行删除的一端称为队头(front),删除动作称为出队
  队列的性质:先进先出(First-in, First-out)

  双向队列:队列的两端都允许进行进队和出队操作。
复制代码

 

 

复制代码
队列实现:
  使用方法:from collections import deque
  创建队列:queue = deque(li)
  进队:append
  出队:popleft
  双向队列队首进队:appendleft
  双向队列队尾进队:pop

队列的实现原理
  普通队列:
    初步设想:列表+两个下标指针
    创建一个列表和两个变量,front变量指向队首,rear变量指向队尾。初始时,front和rear都为0。
    进队操作:元素写到li[rear]的位置,rear自增1。
    出队操作:返回li[front]的元素,front自减1。
复制代码

复制代码
 环形队列:
    改进方案:将列表首尾逻辑上连接起来。
    环形队列:当队尾指针front == Maxsize + 1时,再前进一个位置就自动到0。
    实现方式:求余数运算
    队首指针前进1:front = (front + 1) % MaxSize
    队尾指针前进1:rear = (rear + 1) % MaxSize
    队空条件:rear == front
    队满条件:(rear + 1) % MaxSize == front
复制代码

 

 


 队列的内置模块:

复制代码
使用方法:from collections import deque
    创建队列:queue = deque(li)
    进队:append
    出队:popleft
    双向队列队首进队:appendleft
    双向队列对尾出队:pop
复制代码

 链表:

复制代码
链表中的每一个元素都是一个对象,每个对象称之为一个节点,包含有数据域key和指向下一个节点的指针next。通过各个节点之间的相互连接,最终串联成一个链表。
节点定义:
 class Node(object):
    def __init__(self,item):
        self.item = item
        self.next = None
复制代码

建立链表有两种方式(头插法和尾插法):

复制代码
链表可以有遍历操作:
链表节点的插入和删除:
1、插入
    p.next = curNode.next     #要插入的下一个为curNode的下一个,也就是3
    curNode.next = p          #curNode的下一个为p,也就是刚刚插入的那个,
2、删除
    p = curNode.next       #p为curNode的下一个节点
    curNode.next = curNode.next.next    #curNode的下一个节点=curNode.next.next(变相的赋值)
    del p    #最后删除中间那个碍眼的家伙
复制代码

双向链表:

复制代码
定义:双链表中的每个节点都有两个指针:一个指向后边的节点、一个指向前面的节点。
代码定义:
class Node(object):
    def __init__(self,item=None):
        self.item = item      #当前节点
        self.next = None     #下一个
        self.prior = None     #前一个
复制代码

复制代码
双链表节点的插入和删除(感觉很绕)
插入:
    p.next = curNode.next    #p的下一个=curNode的下一个
    curNode.next.prior = p    #curNode的下一个的前一个=p
    p.prior = curNode          #q的前一个就是curNode
    curNode.next = p            #之后curNode的下一个就是p
删除:
    p = curNode.next             #p是curNode的下一个
    curNode.next = p.next          #赋值   curNode的下一个就是p的下一个
    p.next.prior = curNode          #p的下一个的前一额就是curNode
    del p                            #删除p,赋值成功
复制代码

复制代码
链表-复杂度分析:
列表与链表:
    暗元素值查找
    按下表查找
    在某元素后插入
    删除某元素
复制代码

哈希表:

复制代码
哈希表(hash table,又称为散列表),是一种线性表的存储结构。哈希表有一个顺序表(也就是数组)和一个哈希函数组成(哈希函数就是加密算法,顺序表就是加密后的值)。
哈希函数h(k) 将元素k作为自变量,返回元素的存储下标。 简单的哈希函数: 除法哈希:h(k)
= k mod m #对m取余 乘法哈希:h(k) = floor(m(kA mod 1)) 0<A<1
复制代码

假设有一个长度为7的数组,河西函数h(k) = K%7.元素集合{14,22,3,5}的存储方式如下图(制作图片链接https://visualgo.net/en)。

复制代码
哈希冲突:
    由于哈希表的大小是有限的,而要存储的值得总数量是无线的,因此对于任何哈希函数,都会出现两个不同的元素映射到同一个位置上的情况,这种情况就叫做哈希冲突。
解决哈希冲突--开放寻址法:
    开放寻址法:如果哈希函数返回的位置已经有值,则可以向后探查新的位置来存储这个值。
        线性探查:如果位置i被占用,则探查i+1,i+2·····
        二次探查:如果位置i被占用,则探查i+1²,i-1²,i+2²···
        二度哈希:有n个哈希函数,当使用第一个哈希函数h1发生冲突时,则尝试使用h3,h3等
拉链法:哈希表每个位置都链接一个链表,当冲突发生时,冲突的元素讲被加到该位置链表的最后(图示略)

复制代码

哈希表在python中的应用

 

字典与集合都是通过哈希表来实现的
在python中的字典;
    ls = {"name":"username","password":"password"}
使用哈希表存储字典,通过哈希函数将字典的键映射为下标
在字典键值对数量不多的情况下,几乎不会发生类似于哈希冲突,此时查找一个元素的时间复杂度为O(1)

二叉树:

复制代码
二叉树的链式存储:将二叉树的节点定义为一个对象,节点之间通过类似链表的链接方式来链接。
节点定义:
 class BiTreeNode(object):
    def __init__(self,data):
        self.data = data
        self.lchild = None      #左边的孩纸
        self.rchild = None     #右边的孩纸
二叉树的遍历方式:
    前序遍历:
    中序遍历:
    后序遍历:
    层次遍历:

from collections import deque



class BiTreeNode:
  def __init__(self, data):
    self.data = data
    self.lchild = None
    self.rchild = None


a = BiTreeNode('A')
b = BiTreeNode('B')
c = BiTreeNode('C')
d = BiTreeNode('D')
e = BiTreeNode('E')
f = BiTreeNode('F')
g = BiTreeNode('G')


e.lchild = a
e.rchild = g
a.rchild = c
c.lchild = b
c.rchild = d
g.rchild = f


root = e


#前序遍历
def pre_order(root):
if root:
print(root.data, end='')
pre_order(root.lchild)
pre_order(root.rchild)
#中序遍历
def in_order(root):
if root:
in_order(root.lchild)
print(root.data, end='')
in_order(root.rchild)


#后续遍历
def post_order(root):
if root:
post_order(root.lchild)
post_order(root.rchild)
print(root.data, end='')


#层次遍历
def level_order(root):
queue = deque()
queue.append(root)
while len(queue) > 0:
node = queue.popleft()
print(node.data,end='')
if node.lchild:
queue.append(node.lchild)
if node.rchild:
queue.append(node.rchild)

pre_order(root)
print("")
in_order(root)
print("")
post_order(root)
print("")
level_order(root)

遍历完之后比对他们的打印结果你会发现都是不同的
复制代码

二叉搜索树:

 

复制代码
二叉搜索树是一颗二叉树且满足性质:
设x是二叉树的一个节点。如果y是x左子树的一个节点,那么y.key<= x.key;
如果y是x右子树的一个节点,那么y.key>=x.key.
二叉搜索树的创建
二叉搜索树的遍历(采用中序序列遍历)
二叉搜索树的查询、插入、删除操作
ps:随机化的二叉搜索树,AVL树
复制代码

AVL树:avl树是一个自平衡的二叉搜索树。

具有的性质:

        根的左右子树的高度之差的绝对值不能超过1

        根的左右子树都是平衡二叉树

AV领的实现方式:旋转(在我上边留的网站自己测试,很诡异,了解即可):

B树(B-Tree):B树是一颗自平衡的多路搜索树。常用于数据库的索引。

   

 

python中的位运算符:

位运算符要比乘除法更快,深得广大程序员的喜爱

 

数据结构-实例代码

栈的应用-迷宫问题

给一个二维列表,表示迷宫(0表示通道,1表示围墙),给出算法,求一条走出迷宫的路径。

复制代码
from collections import deque
两种思路:基于堆栈、基于队列
基于堆栈:在一个迷宫节点(x,y)上,可以进行四个方向的探查:maze[x-1][y],maze[x+1][y],maze[x][y-1],maze[x][y+1]
解决思路:从一个节点开始,任意找下一个可以走的点,当找不到的时候,退回上一个点寻找其他方向的点
方法:创建一个空的栈,首先从入口位置进栈,当栈不空的时候循环:获取栈顶元素,寻找下一个可以走的相邻
的方块,说明当前的额位置是死胡同,进行回溯(就是讲当前的位置出栈,看前边的点有没有可以走的路)
  
基于队列:
思路:从一个节点开始,寻找所有下面能继续走的点,继续寻找,知道找到出口。
方法:创建一个空的队列,从起点位置进队,在队列不为空的时候循环:出队一次。如果当前位置为出口,结束算法 否则找出当前方块的四个相邻的方块中可以走的方块,全部进队。
maze
= [ [1,1,1,1,1,1,1,1,1,1], [1,0,0,1,0,0,0,1,0,1], [1,0,0,1,0,0,0,1,0,1], [1,0,0,0,0,1,1,0,0,1], [1,0,1,1,1,0,0,0,0,1], [1,0,0,0,1,0,0,0,0,1], [1,0,1,0,0,0,1,0,0,1], [1,0,1,1,1,0,1,1,0,1], [1,1,0,0,0,0,0,0,0,1], [1,1,1,1,1,1,1,1,1,1] ] dirs = [ lambda x,y:(x-1,y), # lambda x,y:(x,y+1), # lambda x,y:(x+1,y), # lambda x,y:(x,y-1), # ] def solve_maze(x1, y1, x2, y2):
  """基于栈实现""" stack
= [] stack.append((x1,y1)) maze[x1][y1] = 2 while len(stack) > 0: # 当栈不空循环 cur_node = stack[-1] if cur_node == (x2,y2): #到达终点 for p in stack: print(p) return True for dir in dirs: next_node = dir(*cur_node) if maze[next_node[0]][next_node[1]] == 0: #找到一个能走的方向 stack.append(next_node) maze[next_node[0]][next_node[1]] = 2 # 2表示已经走过的点 break else: #如果一个方向也找不到 stack.pop() else: print("无路可走") return False def solve_maze2(x1,y1,x2,y2):
"""基于队列来实现""" queue
= deque() path = [] # 记录出队之后的节点 queue.append((x1,y1,-1)) maze[x1][y1] = 2 while len(queue) > 0: cur_node = queue.popleft() path.append(cur_node) if cur_node[0] == x2 and cur_node[1] == y2: #到终点 real_path = [] x,y,i = path[-1] real_path.append((x,y)) while i >= 0: node = path[i] real_path.append(node[0:2]) i = node[2] real_path.reverse() for p in real_path: print(p) return True for dir in dirs: next_node = dir(cur_node[0], cur_node[1]) if maze[next_node[0]][next_node[1]] == 0: queue.append((next_node[0], next_node[1], len(path)-1)) maze[next_node[0]][next_node[1]] = 2 # 标记为已经走过 else: print("无路可走") return False solve_maze2(1,1,8,8) #输入起点的位置和终点的位置
复制代码

 

。。。。。。。。。。有时间更新

 

posted @ 2018-08-07 22:20  GuoXY  阅读(539)  评论(0编辑  收藏  举报