数据结构

数据结构

数据结构

数据结构的定义

我们如何把现实中大量而且非常复杂的问题以特定的数据类型(个体)和特定的存储结构(个体的关系)保存到相应的主存储器(内存)中,以及在此基础上为实现某个功能而执行的相应操作,这个相应的操作也叫做算法
数据结构 == 个体 + 个体的关系

数据结构的特点

数据结构是软件中最核心的课程
程序 = 数据的存储 + 数据的操作 + 可以被计算机执行的语言

线性结构

把所有的节点用一根线串起来

数组和链表的区别

数组需要一块连续的内存空间来存储,对内存的要求比较高。如果我们申请一个 100MB 大小的数组,当内存中没有连续的、足够大的存储空间时,即便内存的剩余总可用空间大于 100MB,仍然会申请失败。 而链表恰恰相反,它并不需要一块连续的内存空间,它通过“指针”将一组零散的内存块串联起来使用,所以如果我们申请的是 100MB 大小的链表,根本不会有问题。

连续存储(数组)

数组具有索引,可以根据首个数据的内存地址和每个数据占得长度,直接查询到索引对应的存储位置

数组的优缺点:
优点:
存取速度快
缺点:
事先需要知道数组的长度
需要大块的连续内存
插入删除非常慢,效率低

离散存储(链表)

定义:

  • n个节点离散分配
  • 彼此通过指针相连
  • 每个节点只有一个前驱节点,每个节点只有一个后续节点
  • 首节点没有前驱节点,尾节点没有后续节点

优点:

  • 空间没有限制,插入删除元素很快

缺点:

  • 查询比较慢

专业术语:

  • 首节点:第一个有效节点
  • 尾节点:最后一个有效节点
  • 头节点:第一个有效节点之前的那个节点,头结点不存储任何数据
  • 头指针:指向头结点的指针变量
  • 尾指针:指向尾节点的指针变量

链表的分类:

  • 单链表
  • 双链表 每个节点有两个指针域
  • 循环链表 能通过任何一个节点找到其他所有的节点
  • 非循环链表

对链表的操作:

  • 增加
  • 删除
  • 修改
  • 查找
  • 总长度
单链表
class Hero:
    def __init__(self, name=None, no=None, nickname=None, pNext=None):
        self.name = name
        self.no = no
        self.nickname = nickname
        self.pNext = pNext


def add(head, pnew):
    cur = head
    # 直接添加到尾部
    # while cur.pNext != None:
    #     cur = cur.pNext
    # # 此时跳出循环,将新的英雄赋给pNext
    # cur.pNext = pnew

    # 指定位置进行添加
    while cur.pNext != None:
        if cur.pNext.no > pnew.no:
            break
        cur = cur.pNext

    pnew.pNext = cur.pNext
    cur.pNext = pnew


def delHero(head, no):
    cur = head
    while cur.pNext != None:
        if cur.pNext.no == no:
            break
        cur = cur.pNext
    else:
        print('没有找到元素')

    cur.pNext = cur.pNext.pNext


def is_empty(head):
    if head.pNext != None:
        return False
    else:
        return True


def length(head):
    cnt = 0
    cur = head
    while cur.pNext != None:
        cnt = cnt + 1
        cur = cur.pNext
    return cnt


def getAll(head):
    cur = head
    while cur.pNext != None:
        cur = cur.pNext
        print('编号是:%s, 姓名是:%s, 外号:%s' % (cur.no, cur.name, cur.nickname))


head = Hero()
View Code

 

循环链表

约瑟夫问题

设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列

class Child(object):
    first = None

    def __init__(self, data=None, pNext=None):
        self.data = data
        self.pNext = pNext

    def add(self, num):
        cur = None
        for i in range(num):
            child = Child(i + 1)
            if i == 0:
                self.first = child
                self.first.pNext = self.first
                cur = self.first
            else:
                cur.pNext = child
                child.pNext = self.first
                cur = cur.pNext

    def showAll(self):
        cur = self.first
        while cur.pNext != self.first:
            print('小孩的编号是:%s' % cur.data)
            cur = cur.pNext
        print('小孩的编号是:%s' % cur.data)

    def countChild(self, m, k):
        tail = self.first
        while tail.pNext != self.first:
            tail = tail.pNext

        # 退出循环的话,已经到了最后一个小朋友
        for i in range(k - 1):
            self.first = self.first.pNext
            tail = tail.pNext

        # 数两下,相当于tail和first分别移动一下
        # 数三下, 相当于tail和first分别移动2下
        while tail != self.first:  # 退出循环的时候, 圈子里面只剩一个人
            for i in range(m - 1):
                self.first = self.first.pNext
                tail = tail.pNext

            self.first = self.first.pNext
            tail.pNext = self.first

        print('留在圈子里面的小孩编号:%s' % tail.data)


child = Child()

child.add(1000)
child.showAll()
child.countChild(1000, 300)
# 设置tail原因:用来判断循环列表中是否只剩一个值。
View Code

栈的定义

一种可以实现“先进后出”的存储结构

Alt text

栈的分类
  • 静态栈
    – 静态栈的核心是数组,类似于一个连续内存的数组
  • 动态栈
    – 动态栈的核心是链表
栈的算法
  • 初始化
  • 压栈
  • 出栈
  • 判空
  • 遍历
  • 清空
class Stack(object):
    def __init__(self):
        self.pTop = None
        self.pBottom = None
        
    def push(self, new):
        new.pNext = self.pTop
        self.pTop = new
        
    def pop(self):
        if not self.is_empty:
            self.pTop = self.pTop.pNext
        else:
            print('is none')
            
    def getAll(self):
        cur = self.pTop
        while cur != self.pBottom:
            print(cur.data)
            cur = cur.pNext
            
    def is_empty(self):
        if self.pTop == self.pBottom:
            return True
        else:
            return False
            
    def clear(self):
        if self.is_empty(self):
            return None
        p = self.pTop
        q = None
        while p != self.pBottom:
            q = p.pNext
            del p
            p = q
        else:
            self.pBottom = self.pTop
            
class Node(object):
    def __init__(self, data=None, pNext = None):
        self.data = data
        self.pNext = pNext

head = Node()
s = Stack()
s.pTop = s.pBottom = head
View Code
栈的应用
  • 函数的调用
  • 浏览器的前进与后退
  • 表达式的求值
  • 内存分配
  • 走迷宫

队列

队列的定义

一种可以实现“先进先出”的存储结构

队列算法
class Node:
    def __init__(self, value):
        self.data = value
        self.next = None
        
class Queue:
    def __init__(self):
        self.front = Node(None)
        self.rear = self.front
        
    def enQueue(self, element):
        n = Node(element)
        self.rear.next = n
        self.rear = n
        
    def deQueue(self):
        if self.empty():
            print('队空')
            return
        temp = self.front.next
        self.front = self.front.next
        if self.rear == temp:
            self.rear = self.front
        del temp
        
    def getHead(self):
        if self.empty():
            print('队空')
            return
        return self.front.next.data
        
    def empty(self):
        return self.rear == self.front
        
    def printQueue(self):
        cur = self.front.next
        while cur != None:
            print(cur.data)
            cur = cur.next
            
    def length(self):
        cur = self.front.next
        count = 0
        while cur != None:
            count += 1
            cur = cur.next
        return count
View Code
队列的应用
  • 所有和时间有关的操作都和队列有关

树的定义
  • 树有且仅有一个根节点
  • 有若干个互不相交的子树,这些子树本身也是一颗树
树的专业术语
  • 节点
  • 父节点
  • 子节点
  • 子孙
  • 堂兄弟
  • 兄弟
  • 深度
    – 从根节点到最底层节点的层数被称为深度,根节点是第一层
  • 叶子节点
    – 没有子节点的节点

  • – 子节点的个数
树的分类
  • 一般树
    – 任意一个节点的子节点的个数不受限制
  • 二叉树
    – 定义:任意一个节点的子节点个数最多是两个,且子节点的位置不可改变
    — 满二叉树:在不增加层数的前提下,无法再多添加一个节点的二叉树
    — 完全二叉树:只是删除了满二叉树最底层最右边连续的若干个节点
    — 一般二叉树
    -森林
    – n个互不相交的树的集合

二叉树的遍历方法

1.二叉树的先序遍历[先访问根节点]

  • 先访问根节点
  • 再先序遍历左子树
  • 再先序遍历右子树

2.二叉树的中序遍历 [中间访问根节点]

  • 先中序遍历左子树
  • 再访问根节点
  • 再中序遍历右子树

3.二叉树的后序遍历[最后访问根节点]

  • 先后序遍历左子树
  • 再后序遍历右子树
  • 再访问根节点
#### 例一
先序:ABCDEFGH
中序:BDCEAFHG
求后序?
,,,,,
后序:DECBHGFA
#### 例二
中序:BDCEAFHG
后序:DECBHGFA
求先序?
先序:ABCDEFGH
class Node(object):
    """节点类"""
    def __init__(self, elem=-1, lchild=None, rchild=None):
        self.elem = elem
        self.lchild = lchild
        self.rchild = rchild
        
class Tree(object):
    """树类"""
    def __init__(self):
        self.root = Node()
        self.myli = []
    def add(self, elem):
        """为树添加节点"""
        node = Node(elem)
        if self.root.elem == -1:  # 如果树是空的,则对根节点赋值
            self.root = node
            self.myli.append(self.root)
        else:
            treeNode = self.myli[0]  # 此结点的子树还没有齐。
            if treeNode.lchild == None:
                treeNode.lchild = node
                self.myli.append(treeNode.lchild)
            else:
                treeNode.rchild = node
                self.myli.append(treeNode.rchild)
                self.myli.pop(0)
                
    def front_digui(self, root):
        """利用递归实现树的先序遍历"""
        if root == None:
            return
        print(root.elem)
        self.front_digui(root.lchild)
        self.front_digui(root.rchild)
        
    def middle_digui(self, root):
        """利用递归实现树的中序遍历"""
        if root == None:
            return
        self.middle_digui(root.lchild)
        print(root.elem)
        self.middle_digui(root.rchild)
        
    def later_digui(self, root):
        """利用递归实现树的后序遍历"""
        if root == None:
            return
        self.later_digui(root.lchild)
        self.later_digui(root.rchild)
        print(root.elem)
View Code
树的应用
  • 树是数据库中数据组织的一种重要形式
  • 操作系统父子进程的关系本身就是一棵树
  • 面向对象语言中类的继承关系

转载于:https://www.cnblogs.com/luck-L/p/10004053.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值