本节目录

基础数据结构

    • 1、列表/数组
    • 2、链表
    • 3、哈希表
    • 4、跳表
    • 5、栈
    • 6、队列
    • 7、树

高级数据结构

    • 1、优先队列
    • 2、图
    • 3、前缀树
    • 4、线段树
    • 5、树状数组

什么是数据结构?

  • 数据结构是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成。

  • 简单来说,数据结构就是设计数据以何种方式组织并存储在计算机中。

  • 比如:列表、集合与字典等都是一种数据结构。

  • N.Wirth:程序=数据结构+算法

  • 数据结构分为逻辑结构和物理结构

    • 数据结构按照其逻辑结构可分为线性结构、树结构、图结构

      • 线性结构:数据结构中的元素存在一对一的相互关系

      • 树结构:数据结构中的元素存在一对多的相互关系

      • 图结构:数据结构中的元素存在多对多的相互关系

基础数据结构

一、 列表/数组

数据结构与算法系列(一)-- 数据结构

数据结构与算法系列(一)-- 数据结构

数据结构与算法系列(一)-- 数据结构数据结构与算法系列(一)-- 数据结构

数据结构与算法系列(一)-- 数据结构数据结构与算法系列(一)-- 数据结构

数据结构与算法系列(一)-- 数据结构

数据结构与算法系列(一)-- 数据结构

数据结构与算法系列(一)-- 数据结构数据结构与算法系列(一)-- 数据结构

 

  • 列表(其他语言交数据)是一种基本数据类型。

  • 列表与数据有两点不同:

    1. 数组元素类型要相同

    2. 数组长度固定

  • 关于列表的问题:

    • 列表中的元素是如何存储的?存储元素的地址以实现存储不同类型的数据元素,每次添加会动态开辟一块新的内存以实现数组长度固定的问题。

    • 列表的基本操作:按下标查找、插入元素、删除元素.....

    • 这些操作的时间复杂度是多少?按下标查找和append为O(1),前插、中间插入和删除为O(n)

  • 扩展:Python的列表是如何实现的?

  • Array

    • java,C++: int a[100]

    • Python: a = [1,2,3]

    • javascript: let a = [1,2,3]

    • Go: a []int{1,2,3}

操作 数组 链表
prepend O(n)/O(1) O(1)
append O(1) O(1)
lookup O(1) O(n)
insert O(n) O(1)
delete O(n) O(1)
  • 优点

    构建⼀个数组⾮常简单

    能让我们在 O(1) 的时间⾥根据数组的下标(index)查询某个元素

  • 缺点

    构建时必须分配⼀段连续的空间

    查询某个元素是否存在时需要遍历整个数组,耗费 O(n) 的时间(其中,n 是元素的个数)

    删除和添加某个元素时,同样需要耗费 O(n) 的时间

二、链表

链表(Linked List)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。

数据结构与算法系列(一)-- 数据结构

        由于不必须按顺序存储,链表在插入的时候可以达到 O(1)的复杂度,比另一种线性表 —— 顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要 O(n)的时间,而顺序表相应的时间复杂度分别是 O(log\ n)和 O(1)。使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。在计算机科学中,链表作为一种基础的数据结构可以用来生成其它类型的数据结构。链表通常由一连串节点组成,每个节点包含任意的实例数据(data fields)和一或两个用来指向上一个/或下一个节点的位置的链接(links)。链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的访问往往要在不同的排列顺序中转换。而链表是一种自我指示数据类型,因为它包含指向另一个相同类型的数据的指针(链接)。

        链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。链表有很多种不同的类型:单向链表,双向链表以及循环链表。链表通常可以衍生出循环链表,静态链表,双链表等。对于链表使用,需要注意头结点的使用。

  • 链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是不像顺序表一样连续存储数据,而是在每一个节点(数据存储单元)里存放下一个节点的位置信息(即地址)。
  • 单向链表:也叫单链表,是链表中最简单的一种形式。链表中的每个元素实际上是⼀个单独的对象,⽽所有对象都通过每个元素中的引⽤字段链接在⼀起。它的每个节点包含两个域,一个信息域(元素域),一个链接域。这个链接指向链表中的下一个结点,而最后一个节点的链接则指向一个空值。表元素域elem用来存放具体的数据,链接域next用来存放下一个节点的位置(python中的标识),变量p指向链表的头结点(首节点)的位置,从p出发能找到表中的任意节点。
  • 双向链表:与单链表不同的是,双链表的每个结点中都含有 两个引⽤字段,一个指向前一个节点(前驱),一个指向后一个节点(后继)。当此节点为第一个节点时,前驱为空,当此节点为尾节点时,后继为空。

链表的存储方式

数据结构与算法系列(一)-- 数据结构

2.1 单链表

数据结构与算法系列(一)-- 数据结构

 

  • 单链表的操作

数据结构与算法系列(一)-- 数据结构

  • 链表是由一系列节点组成的元素集合。每个节点包含两部分,数据域item和指向下一个节点的指针next。通过节点之间的相互连接,最终串联成一个链表。

    class Node(object):
        def __init__(self, item):
            self.item = item
            self.next = None

    数据结构与算法系列(一)-- 数据结构

 

  • 头插法

数据结构与算法系列(一)-- 数据结构

  • 代码
def create_linklist_head(li: list):
    """
    头插法创建链表
    :param li:
    :return:
    """
    head = Node(li[0])
    for elem in li[1:]:
        node = Node(elem)
        node.next = head
        head = node
    return head
​
def add(self,item):
    """链表头部添加元素,头插法"""
    node = Node(item)
    node.next = self.__head
    self.__head = node
  • 尾插法

    数据结构与算法系列(一)-- 数据结构

    • 代码

      def create_linklist_tail(li: list):
          """
          创建链表:尾插法
          :param li:
          :return:
          """
          head = Node(li[0])
          tail = head
          for elem in li[1:]:
              node = Node(elem=elem)
              tail.next = node
              tail = tail.next
          return head
      ​
      def append(self,item):
          """链表尾部添加元素,尾插法"""
          node = Node(item)
          if self.is_empty():#链表判空
              self.__head = node
          else:
              cur = self.__head
              while cur.next:
                 cur = cur.next
              cur.next = node
  • 链表节点之间插入

    数据结构与算法系列(一)-- 数据结构

    • 代码

    def insert(self,pos,item): #insert(2,100)
        """指定位置添加元素
        :param pos 从0开始
        """
        if pos<=0:
            self.add(item)
        elif pos>(self.length()-1):
            self.append(item)
        else:
            node = Node(item)
            pre = self.__head
            count = 0
            while count < pos-1:
                pre = pre.next
                count += 1
            #当循环退出后,pre指向pos-1位置
            node.next = pre.next
            pre.next = node
  • 链表节点的删除

    数据结构与算法系列(一)-- 数据结构

    • 代码

      def remove(self, item):
          """删除节点"""
          cur = self.__head
          prev = None
          while cur:
              if cur.elem == item:
                  # 先判断此节点是否是头结点
                  if cur == self.__head:
                      self.__head = cur.next
                  else:
                      prev.next = cur.next
                  break
              else:
                  prev = cur
                  cur = cur.next
  • 链表的遍历

    数据结构与算法系列(一)-- 数据结构

    • 代码

      def print_linklist(head: Node):
          """
          遍历列表
          :param head:
          :return:
          """
          while head:
              if head.next:
                  print(head.elem, end='->')
              else:
                  print(head.elem)
              head = head.next
      ​
      def travel(self):
          """遍历整个链表"""
          cur = self.__head
          while cur:
              if cur.next:
                  print(cur.elem,end="->")
              else:
                  print(cur.elem)
              cur = cur.next
  • 单链表代码示例

    class Node(object):
        """节点"""
        def __init__(self, elem):
            self.elem = elem
            self.next = None
    ​
    ​
    class SingleLinkList(object):
        """单链表"""
        def __init__(self, node=None):
            self.__head = node
    ​
        def __str__(self):
            if not self.__head:
                return 'None'
            else:
                cur = self.__head
                list_str = ''
                while cur:
                    cur_str = '{}->'.format(cur.elem) if cur.next else str(cur.elem)
                    list_str += cur_str
                    cur = cur.next
                return list_str
    ​
        def is_empty(self):
            """链表是否为空"""
            return self.__head is None
    ​
        def length(self):
            """链表长度"""
            # cur游标,用来移动遍历节点
            cur = self.__head
            # count记录数量
            count = 0
            while cur:  # cur.next == None
                cur = cur.next
                count += 1
            return count
    ​
        def travel(self):
            """遍历整个链表"""
            cur = self.__head
            while cur:
                if cur.next:
                    print(cur.elem, end="->")
                else:
                    print(cur.elem)
                cur = cur.next
    ​
        def add(self, item):
            """链表头部添加元素,头插法"""
            node = Node(item)
            node.next = self.__head
            self.__head = node
    ​
        def append(self, item):
            """链表尾部添加元素,尾插法"""
            node = Node(item)
            if self.is_empty():  # 链表判空
                self.__head = node
            else:
                cur = self.__head
                while cur.next:
                    cur = cur.next
                cur.next = node
    ​
        def insert(self, pos, item):  # insert(2,100)
            """指定位置添加元素
            :param pos 从0开始
            """
            if pos <= 0:
                self.add(item)
            elif pos > (self.length() - 1):
                self.append(item)
            else:
                node = Node(item)
                pre = self.__head
                count = 0
                while count < pos - 1:
                    pre = pre.next
                    count += 1
                # 当循环退出后,pre指向pos-1位置
                node.next = pre.next
                pre.next = node
    ​
        def remove(self, item):
            """删除节点"""
            cur = self.__head
            prev = None
            while cur:
                if cur.elem == item:
                    # 先判断此节点是否是头结点
                    if cur == self.__head:
                        self.__head = cur.next
                    else:
                        prev.next = cur.next
                    break
                else:
                    prev = cur
                    cur = cur.next
    ​
        def search(self, item):
            """查询节点是否存在"""
            cur = self.__head
            while cur:
                if cur.elem == item:
                    return True
                cur = cur.next
            return False
    ​
        def index(self, item):
            """查询节点是否存在"""
            cur = self.__head
            count = 0
            while cur:
                if cur.elem == item:
                    return count
                cur = cur.next
                count += 1
            return '{} is not in linklist'.format(item)
    ​
        def value(self, index):
            """查找指定位置的值"""
            if self.is_empty():
                return None
            elif index > self.length() - 1:
                return 'linklist index out of range'
            cur = self.__head
            count = 0
            while count < index:
                count += 1
                cur = cur.next
            return cur.elem
    单链表示例

相关文章: