Python数据结构与算法(3)--基本数据结构

文章目录

  • 基本数据结构
    • 1. 线性结构
      • 1. 栈抽象数据类型及Python实现
      • 2. 队列抽象数据类型及Python实现
      • 3. 双端队列抽象数据类型及Python实现
      • 4. 列表
        • 1.抽象数据类型:无序表List
        • 2.采用链表实现无序表
        • 3. 抽象数据类型:有序表OrderedList
        • 4.链表实现的算法分析

基本数据结构

1. 线性结构

  1. 线性结构定义:线性结构是一种有序数据项的集合,其中每个数据项都有唯一的前驱和后继
    除了第一个没有前驱,最后一个没有后继
    新的数据项加入到数据集中时,只会加入到原有某个数据项之前或之后具有这种性质的数据集,就称为线性结构

  2. 线性结构总有两端,在不同的情况下, 两端的称呼也不同
    左右端,前后端,顶底端

  3. 两端的称呼并不是关键,不同线性结构的关键区别在于数据项增减的方式(有的结构只允许数据项从一端添加,而有的结构则允许数据项从两端移除)

  4. 4个最简单但功能强大的结构:栈Stack,队列Queue,双端队列Deque 和列表List
    这些数据集的共同点在于,数据项之间只存在先后的次序关系,都是线性结构

1. 栈抽象数据类型及Python实现

  1. 栈:一种有次序的数据项集合,在栈中,数据项的加入和移除都仅发生在同一端。这一端叫栈“ 顶top” ,另一端叫栈“ 底base”
  2. 栈:后进先出(LIFO,Last-In First-Out),距离栈底越近的数据项,留在栈中的时间就越长
  3. 栈的特性:反转次序
进栈和出栈的次序正好相反
这种访问次序反转的特性,我们在某些计算机操作上碰到过
    浏览器的“ 后退back”按钮,最先back的是最近访问的网页Word的“ Undo” 按钮,最先撤销的是最近操作
  1. 栈在python中的操作
Stack():创建一个空栈,不包含任何数据项
push(item):将item加入栈顶,无返回值
pop():将栈顶数据项移除,并返回,栈被修改
peek(): “ 窥视” 栈顶数据项,返回栈顶的数据项但不移除,栈不被修改
isEmpty():返回栈是否为空栈
size():返回栈中有多少个数据项

用Python实现ADT Stack

class Stack:
    def __init__(self):
        self.items = []
    def isEmpty(self):
        return self.items == []
    def push(self, item):
        self.items.append(0, item)
    def pop(self):
        return self.items. pop(0)
    def peek(self):
        return self.items[0]
    def size(self) :
        return len(self.items )

ADT Stack的另一个实现
❖不同的实现方案保持了ADT接口的稳定性但性能有所不同,栈顶首端的版本(上),其push/pop的复杂度为O(n),而栈顶尾端的实现(下),其push/pop的复杂度为O(1)

class Stack:
    def __init__(self):
        self.items = []
    def isEmpty(self):
        return self.items == []
    def push(self, item):
        self.items.append( item)
    def pop(self):
        return self.items. pop( )
    def peek(self):
        return self.items[len(self . items)-1]
    def size(self) :
        return len(self.items )
  1. 栈的应用
  • 简单括号匹配
    从左到右扫描括号串,最新打开的左括号,应该匹配最先遇到的右括号。这样,第一个左括号(最早打开),就应该匹配最后一个右括号(最后遇到)这种次序反转的识别,正好符合栈的特性
  • 十进制转换为二进制
    进制转换为二进制,采用的是“除以2求余数” 的算法。将整数不断除以2,每次得到的余数就是由低到高的二进制位。“除以2”的过程,得到的余数是从低到高的次序,而输出则是从高到低,所以需要一个栈来反转次序

2. 队列抽象数据类型及Python实现

  • 队列是一种有次序的数据集合,其特征是:新数据项的添加总发生在一端(通常称为“ 尾rear” 端)而现存数据项的移除总发生在另一端(通常称为“ 首front” 端)
    当数据项加入队列,首先出现在队尾,随着队首数据项的移除,它逐渐接近队首
  • 这种次序安排的原则称为(FIFO:First-in first-out)先进先出或“先到先服务first‐come first‐served”
  • 抽象数据类型Queue由如下操作定义:
Queue():创建一个空队列对象,返回值为Queue对象;
enqueue(item):将数据项item添加到队尾,无返回值;
dequeue():从队首移除数据项,返回值为队首数据项,队列被修改;
isEmpty():测试是否空队列,返回值为布尔值
size():返回队列中数据项的个数。

Python实现ADT Queue

# 采 用 List 来 容纳Queue的数据项
# 将List首端作为队列尾端,List的末端作为队列首端
# enqueue()复杂度为O(n),dequeue()复杂度为O(1)
#首尾倒过来的实现,复杂度也倒过来

class Queue:
    def __init__(self):
        self.items = []

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

    def enqueue(self, item):
        self.items.insert(0,item)

    def dequeue(self):
        return self.items.pop()

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

3. 双端队列抽象数据类型及Python实现

  • 双端队列Deque是一种有次序的数据集,跟队列相似,其两端可以称作“ 首”“ 尾” 端,但deque中数据项既可以从队首加入,也可以从队尾加入;数据项也可以从两端移除。某种意义上说,双端队列集成了栈和队列的能力
  • 但双端队列并不具有内在的LIFO或者FIFO特性
  • deque定义的操作
Deque():创建一个空双端队列
addFront(item):将item加入队首
addRear(item):将item加入队尾
removeFront():从队首移除数据项,返回值为移除的数据项
removeRear():从队尾移除数据项,返回值为移除的数据项
isEmpty():返回deque是否为空
size():返回deque中包含数据项的个数

Python实现ADT Deque

class Deque:
    def __init__(self):
        self.items = []

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

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

    def addRear(self, item):
        self.items.insert(0,item)

    def removeFront(self):
        return self.items.pop()

    def removeRear(self):
        return self.items.pop(0)

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

4. 列表

  • 一种数据项按照相对位置存放的数据集
1.抽象数据类型:无序表List
  • 无序表List的操作
List():创建一个空列表
add(item):添加一个数据项到列表中,假设item原先不存在于列表中
remove(item):从列表中移除item,列表被修改, item原先应存在于表中
search(item):在列表中查找item,返回布尔类型值
isEmpty():返回列表是否为空
size():返回列表包含了多少数据项
append(item):添加一个数据项到表末尾,假设item原先不存在于列表中
index(item):返回数据项在表中的位置
insert(pos,item):将数据项插入到位置pos,假设item原先不存在与列表中,
                同时原列表具有足够多个数据项,能让item占据位置pos
pop():从列表末尾移除数据项,假设原列表至少有1个数据项
pop(pos):移除位置为pos的数据项,假设原列表存在位置pos

2.采用链表实现无序表
  • 为了实现无序表数据结构,可以采用链接表的方案。
  • 虽然列表数据结构要求保持数据项的前后相对位置,但这种前后位置的保持,并不要求数据项依次存放在连续的存储空间
  • 链表实现的最基本元素是节点Node每个节点至少要包含2个信息:数据项本身,以及指向下一个节点的引用信息
    注意next为None的意义是没有下一个节点了,这个很重要
  • 链表实现:节点Node
class Node:
    def __init__(self,initdata):
        self.data = initdata
        self.next = None

    def getData(self):
        return  self.data

    def getNext(self):
        return self.next

    def setData(self,newdata):
        self.data = newdata

    def setNext(self,newnext):
        self.next = newnext
        
# 可以采用链接节点的方式构建数据集来实现无序表
"""链表的第一个和最后一个节点最重要如果想访问到链表中
    的所有节点,就必须从第一个节点开始沿着链接遍历下去"""
"""所以无序表必须要有对第一个节点的引用信息
设立一个属性head,保存对第一个节点的引用空表的head为None"""
class UnorderedList:
    def __init__(self):
        self.head = None
#随着数据项的加入,无序表的head始终指向链条中的第一个节点
"""无序表mylist对象本身并不包含数据项
(数据项在节点中)
其中包含的head只是对首个节点Node的引用"""


# isEmpty add size search remove方法实现
class UnorderedList:
    def __init__(self):
        self.head = None
    def isEmpty(self):
        return  self.head == None
    def add(self,item):
        temp = Node(item)
        temp.setNext(self.head)
        self.head =temp
    def size(self):
        current = self.head
        count = 0
        while current != None
            count = count + 1;
            current = current.getNext()
        return  count
    def search(self,item):
        current = self.head
        found = False
        while current != None and not found:
            if current.getData() == item:
                found = True
            else:
                current = current.getNext()
        return  found
    
    def remove(self,item):
        current = self.head
        previous = None
        found = False
        while not found:
            if current.getData() == item:
                found = True
            else:
                previous = current
                current = current.getNext()
        if previous == None:
            self.head = current.getNext()
        else:
            previous.setNext(current.getNext())
3. 抽象数据类型:有序表OrderedList
  • 有序表是一种数据项依照其某可比性质(如整数大小、字母表先后)来决定在列表中的位置
  • 越“小” 的数据项越靠近列表的头,越靠"前"
  • OrderedList所定义的操作
OrderedList():创建一个空的有序表
add(item):在表中添加一个数据项,并保持整体顺序,此项原不存在
remove(item):从有序表中移除一个数据项,此项应存在,有序表被修改
search(item):在有序表中查找数据项,返回是否存在
isEmpty():是否空表
size():返回表中数据项的个数 index(item):返回数据项在表中的位置,此项应存在
pop():移除并返回有序表中最后一项,表中应至少存在一项
pop(pos):移除并返回有序表中指定位置的数据项,此位置应存在
  • 有序表OrderedList实现
# 同样采用链表方法实现
# Node定义相同
# OrderedList也设置一个head来保存链表表头的引用
"""对于isEmpty/size/remove这些方法,与节点的次序无关 ,所以其实现跟UnorderedList是一样的。
search/add方法则需要有修改"""
class Node:
    def __init__(self,initdata):
        self.data = initdata
        self.next = None

    def getData(self):
        return  self.data

    def getNext(self):
        return self.next

    def setData(self,newdata):
        self.data = newdata

    def setNext(self,newnext):
        self.next = newnext
        
class orderedList:
    def __init__(self):
        self.head = None

    def add(self,item):
        current = self.head
        previous = None
        stop = False
        while current != None and not  stop:
            if current.getData() > item:
                stop = True
            else: 
                previous = current
                current = current.getNext()
            
            temp = Node(item)
            if previous == None:
                temp.setNext(self.head)
                self.head = temp
            else:
                temp.setNext(current)
                previous.setNext(temp)
    def size(self):
        current = self.head
        count = 0
        while current != None:
            count = count + 1;
            current = current.getNext()
        return  count
    def search(self,item):
        current = self.head
        found = False
        stop = False
        while current != None and not found and not stop:
            if current.getData() == item:
                found = True
            else:
                if current.getData() > item:
                    stop = True
                else:
                    current = current.getNext
        return found

    def remove(self,item):
        current = self.head
        previous = None
        found = False
        while not found:
            if current.getData() == item:
                found = True
            else:
                previous = current
                current = current.getNext()
        if previous == None:
            self.head = current.getNext()
        else:
            previous.setNext(current.getNext())
4.链表实现的算法分析
  • 对于链表复杂度的分析,主要是看相应的方法是否涉及到链表的遍历
  • 对于一个包含节点数为n的链表
    isEmpty是O(1),因为仅需要检查head是否为None
    size是O(n),因为除了遍历到表尾,没有其它办法得知节点的数量
    search/remove以及有序表的add方法,则是O(n),因为涉及到链表的遍历,按照概率其平均操作的次数是n/2
    无序表的add方法是O(1),因为仅需要插入到表头
  • 链表实现的List,跟Python内置的列表数据类型,在有些相同方法的实现上的时间复杂度不同
  • 主要是因为Python内置的列表数据类型是基于顺序存储来实现的,并进行了优化

你可能感兴趣的:(数据结构,数据结构,python,算法)