数据结构:八大数据结构学习总篇章

0 引言

想成为一名合格的算法工程师,就要努力学习好数据结构,此乃基础,要牢固掌握(共勉)。数据结构是计算机存储、组织数据的方式。主要研究数据的逻辑结构、物理结构和存储结构。分为线性结构和非线性结构。但这些都是概念性的理论,大部分学习方式是依据常用的八大数据结构(数组,链表,树,队列,栈,堆,散列表,图)来进一步细化学习。

当然,每一种数据结构都有独特的数据存储方式,各有优缺点,设计算法时,结合常用的检索,插入,删除,更新和排序等运算,尽量实现在空间复杂度时间复杂度两方面的最优化。

我个人学习的话,也配合刷题(牛客网,Leetcode);
再配合动态可视化算法网站(https://visualgo.net/zh)‘食用’更佳;
此外,推荐一个Github 50+k star的大佬学习算法的技巧和心得汇总;
最后,就是多刷,多查,多总结,加油!

1 数组(Array)

简单来说,数组就是有序的元素序列。既然其中的元素有序,就能通过索引(下标)快速查询元素,注意数组下标一般是从0开始,常见的数组有一维数组,二维数组,多维数组。

Python语言中列表(list)很类似数组,简单创建一下数组:

# 一维数组
list1 = [0, 1, 2]
# 二维数组
list2 = [[0,1,2],[3,4,5],[7,8,9]]
# 依次类推

数组的特点:

  • 数组是相同的数据类型的元素的集合,但python中的列表可以不同数据类型;
  • 数组中的各元素存储是有先后顺序的,因此很适合频繁检索,快速查找;
  • 数组需要提前申请空间,故空间复杂度大,随机访问效率高,故时间复杂度小;

数组的优点:

  1. 按照索引查询元素速度快;
  2. 能存储大量数据;
  3. 按照索引遍历数组方便。

数组的缺点:

  1. 按照内容查找元素速度慢;
  2. 数组的大小一经确定不能改变;
  3. 数组只能存储一种类型的数据;
  4. 增加、删除元素效率慢

2 链表(Linked List)

记得之前在学C语言时,看到这样说:链表相对于数组更好理解,因为数组是最基本的数据结构,提前设定空间大小,虽然查询较快,但插入元素和删除元素比较麻烦,为了弥补这些缺点,链表应用而生,链表是一种物理存储单元上非连续、非顺序的存储结构,简单来说,链表的空间大小不需要提前设定,是动态扩展的,通过指针可以在任意位置插入和删除元素,效率很高,时间复杂度小;但相应的由于动态的特点,链表的查询比较麻烦,时间复杂度大。

此外,链表主要分为单链表,双向链表和循环链表;

Python语言实现单链表类及一些插入,删除等操作;

class SingleLinkedList(object):
    """单链表类"""
    def __init__(self):
        self.head = None

    def is_empty(self):
        return self.head is None

    def add(self, newdata):
        node = SingleListNode(newdata, _next=self.head)
        self.head = node

    def append(self, newdata):
        node = SingleListNode(newdata)
        if self.is_empty():
            self.head = node
        else:
            cur = self.head
            while cur.next is not None:
                cur = cur.next
            cur.next = node

    def insert(self, pos, newdata):
        """将newdata插入pos位置之后"""
        if pos <= 0:
            self.add(newdata)
        elif pos > self.length() - 1:
            self.append(newdata)
        else:
            node = SingleListNode(newdata)
            cur = self.head
            count = 0
            while count < pos - 1:
                count += 1
                cur = cur.next
            node.next = cur.next
            cur.next = node

    def remove(self, olddata):
        """从单链表中删除所有的olddata"""
        cur = self.head
        pre = None
        while cur is not None:
            if cur.item == olddata:
                if not pre:
                    self.head = cur.next
                else:
                    pre.next = cur.next
                cur = cur.next
            else:
                pre = cur
                cur = cur.next

    def length(self):
        """返回单链表的长度"""
        cur = self.head
        count = 0
        while cur is not None:
            count += 1
            cur = cur.next
        return count

    def travel(self):
        """打印整个单链表
        return
        ------
        ls: list,从前至后的单链表"""
        cur = self.head
        ls = []
        while cur is not None:
            ls.append(cur.item)
            cur = cur.next
        return ls

    def search(self, data):
        cur = self.head
        while cur is not None:
            if cur.item == data:
                return True
            else:
                cur = cur.next
        return False

链表的优点:

  1. 任意位置插入或删除元素的速度快,时间复杂度 o ( 1 ) o(1) o(1)
  2. 内存利用率高,不会浪费内存;
  3. 链表的空间大小不固定,可以动态扩展;

链表的缺点:

  1. 随机访问效率低,时间复杂度 o ( n ) o(n) o(n)

总之,和数组的对比:

  1. 如果想要快速访问数据,不经常有插入和删除元素,选择数组;
  2. 如果需要经常的插入和删除元素,而对访问元素时的效率没有很高要求的话,选择链表。

3 树(Tree)

树状图是一种数据结构,由 n ( n > 1 ) n(n>1) n(n>1)个有限结点组成一个具有层次关系的集合,并有以下特点:

  1. 每个结点有零个或多个子结点;
  2. 没有父结点的结点称为根结点;
  3. 每一个非根结点有且只有一个父结点;
  4. 除了根结点外,每个子结点可以分为多个不相交的子树;

树的分类:

  • 无序树:树中任意节点的子结点之间没有顺序关系,这种树称为无序树,也称为自由树;
  • 有序树:树中任意节点的子结点之间有顺序关系,这种树称为有序树;
  • 二叉树:每个节点最多含有两个子树的树称为二叉树;
  • 满二叉树:叶节点除外的所有节点均含有两个子树的树被称为满二叉树;
  • 完全二叉树:有 2 k − 1 2^k-1 2k1 个节点的满二叉树称为完全二叉树;
  • 哈夫曼树(最优二叉树):带权路径最短的二叉树称为哈夫曼树或最优二叉树;

而在算法设计中,用的比较多的就是树的遍历,就是常见的:先序遍历,中序遍历,后序遍历,层次遍历
依据下图:

  • 先序遍历:ABDECF(根-左-右)
  • 中序遍历:DBEAFC(左-根-右)(注:仅二叉树有中序遍历)
  • 后序遍历:DEBFCA(左-右-根)
  • 层次遍历:ABCDEF(同广度优先搜索

Python算法实现:https://blog.csdn.net/MRZHUGH/article/details/107888908

4 队列(Queue)

5 栈(Stack)

栈是允许在同一端进行插入和删除操作的特殊线性表。其中,允许进行插入删除操作的一端称为栈顶(top),另一端为栈底(bottom);栈底固定,而栈顶浮动;栈中元素个数为零时称为空栈。插入一般称为进栈(Push),删除则称为退栈(Pop)。栈也称为先进后出表(First In Last Out, FILO)。

Python实现栈类:

"""
栈类:
栈是有序的LIFO(后进先出);
  1.Stack()创建新的栈;
  2.push(item)添加新的栈元素到顶部;
  3.pop()删除栈顶部并返回栈顶的值,栈被修改;
  4.peek()返回栈顶值,不修改栈;
  5.is_empty()测试栈是否为空,返回布尔值(True,False);
  6.size()返回栈长度;

"""
class Stack(object):
    # 初始化
    def __init__(self):
        self.list = []
        
    # push操作
    def push(self, item):
        # 添加一个新元素到item到栈顶
        self.list.append(item)
        
    # pop操作
    def pop(self):
        # 弹出栈顶元素
        return self.list.pop()
    
    # 返回栈顶元素
    def peek(self):
        print("栈顶元素是:")
        if self.list:
            return self.list[-1]
        else:
            return None
    
    # 判断栈是否为空
    def is_empty(self):
        return self.list == []
    
    # 返回栈的元素个数
    def size(self):
        print("栈的大小:")
        return len(self.list)

实例化:

# 实例化栈并push操作元素
s = Stack()
s.push(1)
s.push(2)
s.push(3)
s.push(4)

判断栈是否为空:

s.is_empty()
False

输出栈顶元素:

s.peek()
栈顶元素是:
4

输出栈的大小:

s.size()
栈的大小:
4

pop弹出栈元素:

# pop弹出元素
# 重复运行四次:依次输出4,3,2,1
s.pop()
1

再次判断栈是否为空:

s.is_empty()
True

6 堆(Heap)

7 散列表(Hash)

8 图(Graph)

Reference

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZPILOTE

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值