Python中常见的数据结构可以统称为容器。序列(如列表和元组)、映射(如字典)以及集合(set)是三类主要的容器。

线性数据结构分类:栈(stack)--先进后出、 队列(queue)-先进先出、双端队列(deque)、链表(LinkedList),Python内置了数据结构常用模块:collections、heapq、operator、itertools,可以满足使用,但对于最基本的结构还是得熟悉。

一、序列(列表、元组和字符串)

序列中的每个元素都有自己的编号。Python中有6种内建的序列。其中列表和元组是最常见的类型。其他包括字符串、Unicode字符串、buffer对象和xrange对象。下面重点介绍下列表、元组和字符串。

可变数据类型
    列表、字典、集合         不可哈希
    集合里存的元素必须是不可变的数据类型,无序,不重复(去重)

不可变数据类型
    元组、数字、字符串       可哈希

列表

元祖

字符串

1、常见的基本操作

  • 增删改查
  • 索引,切片


1.常见的基本操作

  • 增删查(不能修改)
  • 索引,切片

1.常见的基本操作

  • 增删查(不能修改)
  • 索引,切片

列表是可变的,这是它区别于字符串和元组的最重要的特点,一句话概括即:列表可以修改,而字符串和元组不能。元组使用小括号,列表使用方括号。元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可。

二、映射(字典)

映射中的每个元素都有一个名字,如你所知,这个名字专业的名称叫键。字典(也叫散列表)是Python中唯一内建的映射类型。字典的键可以是数字、字符串或者是元组,键必须唯一。在Python中,数字、字符串和元组都被设计成不可变类型,而常见的列表以及集合(set)都是可变的,所以列表和集合不能作为字典的键。键可以为任何不可变类型,这正是Python中的字典最强大的地方。

函数

说明

D

代表字典对象

D.clear()

清空字典

D.pop(key)

移除键,同时返回此键所对应的值

D.copy()

返回字典D的副本,只复制一层(浅拷贝)

D.update(D2)

将字典 D2 合并到D中,如果键相同,则此键的值取D2的值作为新值

D.get(key, default)

返回键key所对应的值,如果没有此键,则返回default

D.keys()

返回可迭代的 dict_keys 集合对象

D.values()

返回可迭代的 dict_values 值对象

D.items()

返回可迭代的 dict_items 对象

三、集合

集合(Set)在Python 2.3引入,通常使用较新版Python可直接创建,如下所示:

strs=set(['jeff','wong','cnblogs'])
nums=set(range(10))

看上去,集合就是由序列(或者其他可迭代的对象)构建的。集合的几个重要特点和方法如下:

(1) 固定集合构造(创建)函数 frozenset

函数

说明

frozenset()

创建一个空的固定集合对象

frozenset(iterable)

用可迭代对象创建一个新的固定集合对象

(2) 集合构造(创建)函数 set

函数

说明

set()

创建一个空的集合对象(不能用{}来创建空集合)

set(iterable)

用可迭代对象创建一个新的集合对象

(3) Python3 集合中常用的方法

方法

意义

S.add(e)

在集合中添加一个新的元素e;如果元素已经存在,则不添加

S.remove(e)

从集合中删除一个元素,如果元素不存在于集合中,则会产生一个KeyError错误

S.discard(e)

从集合S中移除一个元素e,在元素e不存在时什么都不做;

S.clear()

清空集合内的所有元素

S.copy()

将集合进行一次浅拷贝

S.pop()

从集合S中删除一个随机元素;如果此集合为空,则引发KeyError异常

S.update(s2)

用 S与s2得到的全集更新变量S

S.difference(s2)

用S - s2 运算,返回存在于在S中,但不在s2中的所有元素的集合

S.difference_update(s2)

等同于 S = S - s2

S.intersection(s2)

等同于 S & s2

S.intersection_update(s2)

等同于S = S & s2

S.isdisjoint(s2)

如果S与s2交集为空返回True,非空则返回False

S.issubset(s2)

如果S与s2交集为非空返回True,空则返回False

S.issuperset(...)

如果S为s2的子集返回True,否则返回False

S.symmetric_difference(s2)

返回对称补集,等同于 S ^ s2

S.symmetric_difference_update(s2)

用 S 与 s2 的对称补集更新 S

S.union(s2)

生成 S 与 s2的全集

四、线性存储(栈、队列、链表)

堆栈:先进后出        队列:先进先出 FIFO       

(1)利用提供的栈和队列模块

python自带的list就是以栈为基础构建的,

'''栈stack 先进后出FILO (first in last out)   没有找到import stack这种方法'''
##栈:增(插)、删、改、查
lst=[]
lst.append("zhangsan")
print("增:",lst)
lst.insert(0,"wangwu")
print("插:",lst)
lst.pop()  ###pop()默认会弹出栈尾数据,pop(0)会弹出栈首数据 
print("删:",lst)
lst[0]="lisi"
print("改:",lst)
print(lst.index("lisi"))  ###这是list的查方法,存在则返回索引,否则报错

而队列需要借助第三方包来实现,put压入,get弹出,但是不能直接实现定点插入、修改或删除,因为这样突破了队列先进先出的特性,如果需要操作,需要将队列的元素先取出在压入。

'''普通队列 先进先出 进: put() 出: get(),大小full() empty() qsize(), maxsize'''
import queue  ###python3,而python2为import Queue

q = queue.Queue() # 创建队列,初始没有设置则可以无限添加,设置大小后就需要考虑队列满插入和队列空弹出操作
q.put("张一山")
q.put("王大拿")
q.put("王木生")
print(q.get()) ##输出张一山
print(q.get()) ##输出王木拿
print(q.get()) ##输出王木生

qq = queue.Queue(8)
# print(dir(qq))
try:
    for i in range(12):
        myData = 'A'
        qq.put(myData,block=False)
        myData = 'B'
except Exception as e:
    print(e)

while qq.empty()!=True:
    print(qq.get())


'''
双端队列(两边都可以进和出) 
进: append()和appendleft()
出: pop()和popleft()
'''
from collections import deque

d = deque()
d.append("牡丹花")
d.appendleft("樱桃花")
d.append("腊梅")
d.append("兰花")
d.appendleft("罂粟花")
print(d.pop())   # "兰花"
print(d.popleft())  # "罂粟花"
print(d.pop())  # "腊梅"
print(d.popleft())    # "樱桃花"
print(d.popleft())  # "牡丹花"

补充一点就是,当设置了队列长度后,Queue.put()默认有 block = True 和 timeout 两个参数。当  block = True 时,写入是阻塞式的,阻塞时间由 timeout  确定。正因为阻塞,才导致了后来的赋值污染了处于阻塞状态的数据。Queue.put()方法加上 block=False 的参数,即可解决这个隐蔽的问题。但要注意,非阻塞方式写队列,当队列满时会python2会抛出 exception Queue.Full 的异常。

(2)用list来分别构建栈和队列

从某种角度来说,栈和队列可以看作操作受限的list,具有操作如下,

###利用列表构建一个栈
class Stack():
    def __init__(self):
        self.items = [] # 初始化一个列表

    def is_empty(self):  # 如果为空则返回True 否则返回False
        return self.items == []

    def pop(self):
        try:
            return self.items.pop()
        except:
            raise

    def push(self, item):
        self.items.append(item)

    def peek(self):       # 返回栈顶的元素
        return self.items[len(self.items)-1]

    def size(self):
        return len(self.items)


###利用列表构建一个队列
class Queue():
    def __init__(self):
        self.items = []  ##初始化一个队列

    def is_empty(self):
        return self.items == []

    def enqueue(self, item): # 从队尾插入
        self.items.insert(0, item)

    def dequeue(self):       # 从队首弹出
        try:
            return self.items.pop()
        except:
            raise

    def peek(self):
        return self.items[0]

    def size(self):
        return len(self.items)


###用两个栈实现队列的操作
'''
因为栈是先进后出的,队列是先进先出的。那么,设两个栈分别为s1和s2。
当进行入队的时候,可以直接在s1上进行压栈的操作;
当进行出队的时候,因为是先进要先出,因此可以将s1的元素倒出到s2中,然后在s2进行弹栈的操作;
'''
 
class Solution:  
    def __init__(self):
        # 初始化两个栈  
        self.stack1 = []  
        self.stack2 = []  
    def push(self, node):  
        # 直接在s1进行弹栈 
        self.stack1.append(node)  
    def pop(self):
        # 如果s2不为空,则直接进行弹栈    
        if self.stack2:  
            return self.stack2.pop()
        # 如果s2为空,则返回寻找s1中的元素  
        elif not self.stack1:
            # 如果s1为空,则返回空置,没有元素可以弹出  
            return None  
        else:
            # 否则将s1的元素倒入到s2中,再弹栈  
            while self.stack1:  
                self.stack2.append(self.stack1.pop())  
            return self.stack2.pop()

链表:给我一个表头,给你整个世界

链表种类:单向链表、单向循环链表、双向链表、双向循环链表

python set数据结构 python的数据结构有哪几种_元组

常见的链表形式有带头节点的与无头结点的两种形式,

1.        头结点的数据域可以不存储任何信息,也可以存储线性表的长度等附加信息,头结点的指针域存储第一个元素结点的地址,即首元结点的存储地址。若线性表为空表,则头结点的指针域为NULL;

2.        在链表中加入头结点的好处是:

a)        由于首元结点的地址被存放在头结点的指针域中,因此在链表的首元结点和表中其他结点上的操作一致,无需进行特殊处理,使得各种操作方便统一。

b)       即使是空表,头指针也不为空,使得“空表”和“非空表”的处理一致。

class LNode(object):
    #结点初始化函数, p 即模拟所存放的下一个结点的地址
    #为了方便传参, 设置 data,p 的默认值为None
    def __init__(self, data=None, p=None):
        self.data = data
        self.next = p
 
class LinkList(object):
    def __init__(self):
        self.head = None
 
    #链表初始化函数, 方法类似于尾插
    def init_List(self, data):
        #创建头结点
        self.head = LNode(data[0])
        p = self.head
        #逐个为 data 内的数据创建结点, 建立链表
        for i in data[1:]:
            node = LNode(i)
            p.next = node
            p = p.next
 
    #链表判空
    def is_Empty(self):
        if self.head == None:
            return True
        else:
            return False
 
    #取链表长度
    def get_Length(self):
        if self.is_Empty():
            return 0
 
        p = self.head
        len = 0
        while p:
            len += 1
            p = p.next
        return len
 
    #遍历链表
    def trave_List(self):
        if self.is_Empty():
            return
        print ('\rlink list traving result: ')
        p = self.head
        while p:
            print (p.data)
            p = p.next
 
    #链表插入数据函数
    def insert_Elem(self, key, index):
        if self.is_Empty():
            return
        if index<0 or index>self.get_Length()-1:
            print ("\rKey Error! Program Exit.")
            return
 
        p = self.head
        i = 0
        while i<=index:
            pre = p
            p = p.next
            i += 1
 
        #遍历找到索引值为 index 的结点后, 在其后面插入结点
        node = LNode(key)
        pre.next = node
        node.next = p
 
    #链表删除数据函数
    def delete_Elem(self, index):
        if self.is_Empty():
            return
        if index<0 or index>self.get_Length()-1:
            print ("\rValue Error! Program Exit.")
            return
 
        i = 0
        p = self.head
        #遍历找到索引值为 index 的结点
        while p.next:
            pre = p
            p = p.next
            i += 1
            if i==index:
                pre.next = p.next
                p = None
                return 1
 
        #p的下一个结点为空说明到了最后一个结点, 删除之即可
        pre.next = None
 
 
#初始化链表与数据
data = [1,2,3,4,5]
l = LinkList()
l.init_List(data)            
l.trave_List()
 
#插入结点到索引值为3之后, 值为666
l.insert_Elem(666, 3)
l.trave_List()
 
#删除索引值为4的结点
l.delete_Elem(4)
l.trave_List()

五、非线性存储(树、图)

对于常见的非线性存储结构,二叉树的构建,通常会先构建一个节点类,然后再构建树类,具体如下:

class BTNode(object):
    def __init__(self, key=None, lchild=None, rchild=None):
        self.key = key
        self.lchild = lchild
        self.rchild = rchild

class BiTree(object):
    def __init__(self, data_list):
        #初始化即将传入的列表的迭代器
        self.it = iter(data_list)

    def createBiTree(self, bt=None):    
        try:
            #步进获取下一个元素
            next_data = next(self.it)
            #如果当前列表元素为'#', 则认为其为 None
            if next_data is "#":
                bt = None
            else:
                bt = BTNode(next_data)
                bt.lchild = self.createBiTree(bt.lchild)
                bt.rchild = self.createBiTree(bt.rchild)
        except Exception as e:
            print(e)

        return bt

    #先序遍历函数
    def preOrderTrave(self, bt):
        if bt is not None:
            print(bt.key, end=" ")
            self.preOrderTrave(bt.lchild)
            self.preOrderTrave(bt.rchild)

    #中序遍历函数
    def inOrderTrave(self, bt):
        if bt is not None:
            self.inOrderTrave(bt.lchild)
            print(bt.key, end=" ")
            self.inOrderTrave(bt.rchild)

    #后序遍历函数
    def postOrderTrave(self, bt):
        if bt is not None:
            self.postOrderTrave(bt.lchild)
            self.postOrderTrave(bt.rchild)
            print(bt.key, end=" ")
     
    #层序遍历
    def cengTrave(self,bt):
        if bt==None:
            return 
        else:
            q=[bt]
            while q:
                node=q.pop(0)
                print(node.key,end=' ')
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
            

    #综合打印
    def printTrave(self, bt):
        print("先序遍历: ", end="")
        self.preOrderTrave(bt)
        print('\n')
        print("中序遍历: ", end="")
        self.inOrderTrave(bt)
        print('\n')
        print("后序遍历: ", end="")
        self.postOrderTrave(bt)
        print('\n')


data = input("Please input the node value: ")
data_list = list(data)

btree = BiTree(data_list)
root = btree.createBiTree()
btree.printTrave(root)

或者整合在一起:

class BinaryTree:
    def __init__(self,rootObj):
        self.key = rootObj
        self.leftChild = None
        self.rightChild = None
 
    def insertLeft(self,newNode):
        if self.leftChild == None:
            self.leftChild = BinaryTree(newNode)
        else:
            t = BinaryTree(newNode)
            t.leftChild = self.leftChild
            self.leftChild = t
 
    def insertRight(self,newNode):
        if self.rightChild == None:
            self.rightChild = BinaryTree(newNode)
        else:
            t = BinaryTree(newNode)
            t.rightChild = self.rightChild
            self.rightChild = t
 
 
    def getRightChild(self):
        return self.rightChild
 
    def getLeftChild(self):
        return self.leftChild
 
    def setRootVal(self,obj):
        self.key = obj
 
    def getRootVal(self):
        return self.key
 
 
r = BinaryTree('a')
print(r.getRootVal())
print(r.getLeftChild())
r.insertLeft('b')
print(r.getLeftChild())
print(r.getLeftChild().getRootVal())
r.insertRight('c')
print(r.getRightChild())
print(r.getRightChild().getRootVal())
r.getRightChild().setRootVal('hello')
print(r.getRightChild().getRootVal())

至于图结构 (参考链接:)

创建图有3种方式

1,邻接矩阵

2,邻接集合

3,邻接字典

# coding=utf8
 
# 对5个顶点进行排序
a, b, c, d, e = range(5)
# 顶点个数
N = 5
 
G = [[0] * N for _ in xrange(N)]
 
# 邻接矩阵
# 存储数据有大量空的数据,全是0的情况,在查找某一个顶点的邻接顶点就会遍历所有的顶点
def add_edge(G, v1, v2):
    G[v1][v2] = G[v2][v1] = 1
 
add_edge(G, a, b)
add_edge(G, a, e)
add_edge(G, b, e)
add_edge(G, b, d)    
add_edge(G, b, c)
add_edge(G, c, d)
add_edge(G, d, e)
 
print(G)
 
 
#更多情况,我们是采用邻接集合和邻接字典来存储
# 邻接集合
# 每一个顶点只记录其邻接顶点
G2 = [{b, e},          # a
      {a, e, b, c},    # b
      {b, d},          # c
      {b, c, e},       # d
      {a, b, d}        # e
      ]
print(G2)
 
# 带权的边,利用邻接字典存储
G3 = [{b: 4, e: 2},              # a
      {a: 4, e: 3, d: 6, c: 5},  # b
      {b: 5, d: 7},              # c
      {b: 6, c: 7, e: 1},        # d
      {a: 2, b: 3, d: 1}         # e
      ]
 
print(G3)