数据结构与算法总结

数据结构DS

DLSO

逻辑结构

集合,线性表,树,图

存储结构

顺序存储,链式存储,哈希/散列存储

算法

算法是计算机求解特定问题的有限步骤序列。
算法的五特性:有输入、有输出、有穷性、确定性、可行性
好的算法四特点:正确性、可读性、健壮性、高效性

算法性能标准

时间复杂度和空间复杂度
算法分析本质上是做上界O、下界\omega、确界\theta的分析,一般以上界为准,分为常数阶O(1),对数阶O(log2n),线性阶O(n),线性对数阶O(nlog2n),多项式阶,指数阶O(2n)
空间复杂度包括输入数据占用的空间,程序本身占用的空间,辅助变量占用的空间。

线性表

线性结构有唯一的第一元素和最后元素,除此之外的其他元素都有唯一的前驱和后继。顺序存储的线性表又叫顺序表,链式存储的线性表又叫链表。

顺序表

已知存储宽度和顺序表的起始地址,则可计算顺序表每个元素的存储地址。
顺序表的四大基础操作:插入,删除,查找(给值查地址,给地址查值)。

插入

需要向后依次偏移插入位置及之后的顺序表元素,时间复杂度O(n/2)

删除

需要向前依次偏移删除位置及之后的顺序表元素,时间复杂度为O((n-1)/2)

查找

给地址查值:时间复杂度为O(1)
给值查地址:时间复杂度为O((n+1)/2)

(单)链表

链表中每个节点由元素本身的值域和维护它逻辑关系的链域(即指针域)组成,指针指示后继元素存储位置。

特殊用法:头指针h指向头节点,头节点不存储数据,头节点的指针指向第一个元素a1的位置。

增加头节点的原因:保护头指针,使得当链表为空时,头指针仍指向头节点。
链表的四大基础操作:插入,删除,查找(给值查地址,给地址查值)。

插入

只需修改待插入节点前一个及其本身的指针,时间复杂度O(2)

删除

只需修改待删除节点前一个指针,使其指向下一个节点,时间复杂度O(1)

查找

不同于顺序表的存储,查找链表元素及地址需要从头指针依次遍历,等概条件下时间复杂度为O((n+1)/2)

单链表变形结构

  1. 单循环链表:链表尾部指针指向头节点,链表成环,任何节点都能通过指针找到另一个节点
  2. 双向循环链表:拥有两个链域:前驱和后继,查找前后节点的时间复杂度为O(1)

就地逆置算法

  1. 对于顺序表,使用temp变量在循环中交换中间元素两边i和n-1-i的值,时间复杂度O(n/2),只用到temp一个额外空间,空间复杂度O(1)
  2. 对于单链表,用到3个指针list、p、q,list指向旧链表的第一个元素,p指向新链表的第一个元素,q将旧链表取出的节点插入到新链表

运算受限的线性表

队列都受到插入和删除的限制:栈的插入删除只能在线性表的一端进行,满足后进先出原则;队列的插入删除必须分别在线性表的两端进行,满足先进先出原则

栈是特殊的线性表,固定的一端叫做栈底,活动的一端叫做栈顶,指向栈的最后一个元素,用top表示。

栈顶

栈底位置在栈底元素之下,a1是栈底元素,位置为0,故栈底位置为-1,当top=-1时表示空栈,当top不为-1比如top=0时,表示栈中有一个元素且访问下标为0

栈的操作

栈的操作只有两个,入栈push和出栈pop,且都是在栈顶位置进行

满栈不能入,空栈不能出,前者会造成上溢,后者会造成下溢

队列

队列有两个指针,front和rear,front指向队头元素的前一个位置(类似栈底,与元素不在同一位置),rear指向队尾元素

当队列是空队列时,front和rear指向同一个空的空间

顺序队列的空满判定

当一系列元素入队出队后必然会导致rear指针指向队列存储空间尾端,此时若再有元素入队会产生假上溢,可使用模运算将新元素插入front前的位置,则rear将指向front前,当满队时rear与front指向同一个位置,与空队列定义相悖,产生空满判定问题。
三种解决方法:

  1. 设置一个标志位flag(0/1)
  2. 设置一个计数器counter
  3. 少用(牺牲)一个元素的存储空间

链栈、链队列

链栈的实现只需限制链表的插入删除操作只能在链表头进行,即新建指针top指向链表头部节点。
链队列的实现需要限制插入只能在链表尾部进行,删除只能在链表头部进行,即新建rear指针指向队尾节点,队尾节点用front指针指向对头节点。

带尾指针的单循环链表天然就是一个链队列

在这里插入图片描述

树和二叉树

二叉树的递归定义:二叉树或为空树,或是由一个根节点加上两颗分别称为左子树、右子树的互不交叉的二叉树组成。

基本概念

节点的度:节点拥有的子树的个数
二叉树的度:二叉树中最大的节点度数,二叉树的度最大为2
二叉树的深度:二叉树中节点的最大层次数
叶子:度为0的节点称为叶子节点
孩子:节点子树的根
双亲:孩子节点的上层节点
子孙:以某节点为根的子树中任意节点
祖先:从根到某节点所经分支上的所有节点
节点的层次:根节点是第一层,孩子是第二层,孩子的孩子是第三层,以此递推。
兄弟:同一个双亲的孩子称为兄弟
堂兄弟:双亲在同一层的节点
满二叉树:除了叶子节点,其它节点度为2,且所有叶子节点位于同一层的二叉树
完全二叉树:一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为i(1≤i≤n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。

二叉树的性质

  1. 二叉树的第i层最多有2i-1个节点。
  2. 深度为k的二叉树上最多含2k-1个节点
  3. 对任意二叉树,设叶子数为n0,度为2的节点数为n2,则n0=n2+1
  4. 具有n个节点的完全二叉树的深度为【log2n】+1,即log2n向下取整再加一

二叉树的遍历

三种递归遍历+一种非递归遍历:

  1. 先序遍历:先访问根节点,再访问左子树,最后访问右子树
  2. 中序遍历:先访问左子树,再访问根节点,最后访问右子树
#中序遍历Python
def inorder(root):
	if not root:
		return []
	return inorder(root.left)+[root.val]+inorder(root.right)
#返回以中序遍历的数组,若是二叉排序树,数组为升序
  1. 后序遍历:先访问左子树,再访问右子树,最后访问根节点
  2. 层序遍历:同一层从左到右进行遍历,遍历每一层

如果任意给定两种遍历关系,是否能重构唯一的二叉树?
答:中序遍历是必须的,另外一种三选一即可。

二叉树的三种经典算法

:以下算法均用递归实现

  1. 求二叉树深度
    空树:深度=0
    左右子树为空:深度=1
    其它:深度=1+max(左子树深度,右子树深度)
  2. 求二叉树叶子节点个数
    空树:叶子数=0
    左右子树为空:叶子数=1
    其它:叶子数=左子树叶子数+右子树叶子数
  3. 求二叉树节点个数
    空树:节点数=0
    其它:节点数=1+左子树节点数+右子树节点数

特殊的二叉树

二叉排序树BST

特点:节点左子树的所有元素值都小于该节点值,右子树的所有元素值都大于该节点值

对二叉排序树做中序遍历可得一个升序的序列,以此可判断一棵树是否是二叉排序树。

二叉排序树的构造过程
二叉排序树的构造过程是一个查找和插入的过程,二叉排序树中添加任何的节点都是添加叶子的过程

二叉排序树的删除过程

  1. 删除叶子(度为0的节点)
    直接删除
  2. 删除只有左子树或右子树的节点(度为1的节点)
    以其非空孩子节点替代
  3. 删除既有左子树又有右子树的节点(度为2的节点)
    以其前驱节点替代,再删除前驱节点

前驱节点是待删除节点左孩子的最后一个右孩子,即中序遍历的前一个节点,可用while循环找出。

在这里插入图片描述

平衡二叉树AVL

查找二叉排序树中的元素时,发现可以调整树的结构使得平均查找长度ASL的值尽可能小,即降低二叉排序树的高度

特点:每个节点都有一个平衡因子,等于左子树深度-右子树深度,所有节点的平衡因子绝对值小于等于1

平衡二叉树的构造

哈夫曼树

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值