DS_C_School

第1章 绪论

初始数据结构

主教材

国内经典教材

大多数高校考研指定参考书

数据结构(C语言版)-严蔚敏

两本参考书

数据结构(C语言版)(第2版)-殷人昆

数据结构教程(第5版)-李春葆

(特点:讲解清楚)

数据结构是一门研究非数值计算的程序设计问题中计算机的操作对象以及它们之间的关系操作等的学科

基本概念和术语

数据元素是数据的基本单位

数据项是数据的不可分割的最小单位

基本结构

  1. 集合
  2. 线性结构
  3. 树形结构
  4. 图状结构或网状结构

抽象数据类型的表示与实现

算法和算法分析

算法

  1. 有穷性

    一个算法必须总是(对任何合法的输入值)在执行有穷步之后结束,且每一步都可在有穷时间内完成

    (有穷的概念不是纯数学的,而是在实际上是合理的,可接受的)

  2. 确定性

  3. 可行性

  4. 输入

  5. 输出

算法设计的要求

  1. 正确性
  2. 可读性
  3. 健壮性
  4. 效率与低存储量需求

算法效率的量度

算法的存储空间需求

第2章 线性表

线性表的类型定义

线性表的顺序表示和实现

线性表的链式表示和实现

元素(数据元素的映像) + 指针(指示后继元素存储位置的) = 结点(表示数据元素)

以 “结点的序列” 表示线性表- 称作链表

线性链表

重点重点重点

以后不说,默认都是带头结点的链表

头指针,指向链表的起始结点

Status ListInsert L(LinkList L, int pos, ElemType e) {
    // 查找
    p = L; j = 0;
    while(p && j < pos-1) {
        p = p->next; ++j;// 寻找第 pos-1 个结点
    }
    if(!p || j<pos-1)
        return ERROR;// pos小于1或者大于表长
    
    s = (LinkList)malloc(sizeof(LNode));// 生成新结点
    s->data = e; s->next = p->next;// 插入L中
    p->next = s;
    return OK;
}
// 算法的时间复杂度:O(ListLength(L))

用上述定义的单链表实现线性表的操作时,存在的问题:

  1. 单链表的表长是一个隐含的值。
  2. 在单链表的最后一个元素最后插入元素时,需便利整个链表。
  3. 在链表中,元素的 “位序” 概念淡化,结点的 “位置” 概念淡化。

改进链表的设置:

  1. 增加 ”表长“、”表尾指针“ 和 ”当前位置的指针“ 三个数据域。
  2. 将基本操作由 “位序” 改变为 “指针”。

四、一个带头结点的线性链表类型

typedef struct LNode { // 结点类型
    ElemType data;
    struct LNode *next;
} *Link, *Position;
Status MakeNode(Link &p, ElemType e);
// 分配由p指向的值为e的结点,
// 若分配失败,则返回ERROR
void FreeNode(Link &p);
// 释放p所指结点
typedef struct { // 链表类型
    Link head, tail; // 指向头结点和最后一个结点
    int len;		 // 指示链表长度
    Link current;
    // 指向当前访问的结点的指针,
    // 初始位置指向头结点
}

链表的基本操作:

  • 结构初始化和销毁结构
Status InitList(LinkList &L);
// 构造一个空的线性表L,
// 头指针、尾指针和当前指针均指向头结点,表长为零

Status DestroyList(LinkList &L);
// 销毁线性表L,L不再存在
  • 引用型操作
Status ListEmpty(LinkList L);	// 判表空
int ListLength(LinkList L);		// 求表长
Status Prior(LinkList L);		// 改变当前指针指向其前驱
Status Next(LinkList L);		// 改变当前指针指向其后继
ElemType GetCurElem(LinkList L); // 返回当前指针所指数据元素
Status Locatepos(LinkList L, int i); // 改变当前指针指向第i个结点
Status LocateElem(LinkList L, ElemType e, Status(* compare)(ElemType, ElemType));
// 若存在与e满足函数compare()判定关系的元素,则移动当前指针
// 指向第1个满足条件的元素,并返回OK,否则返回ERROR
Status ListTraverse(LinkList L, Status(*visit)());
// 依次对L的每个元素调用函数visit()
  • 加工型操作
Status ClearList(LinkList &L);
// 重置为空表
Status SetCurElem(LinkList &L, ElemType e);
// 更新当前指针所指数据元素
Status Append(LinkList &L, Link s);
// 一串结点链接在最后一个结点之后
Status InsAfter(LinkList &L, ElemType e);
// 将元素e插入在当前指针之后
Status DelAfter(LinkList &L, ElemType *e);
// 删除当前指针之后的结点

循环链表

双向链表

一元多项式的表示及相加

一个结点,不包含本身的指针域(地址),而是包含它的下一个结点的地址(指针域)

第3章 栈和队列

栈的类型定义

  • 初始化和销毁结构
    • InitStack(&S)
    • DestroyStack(&S)
  • 引用型操作
    • StackEmpty(S)
    • StackLength(S)
    • GetTop(S, &e)
  • 加工型操作
    • ClearStack(&S)
    • Push(&S, e)
    • Pop(&S, &e)

栈的应用举例

数制转换

十进制数N 和 其他d进制数 的转换时计算机实现计算的基本问题,其解决方法很多,

其中一个简单算法基于下列原理

N = (N div d) * d + N mod d // 其中:div 为 整数运算, mod为求余运算

假设现要编制一个满足下列要求的程序,对于输入的任意一个非负十进制整数,打印输出与其等值的八进制数。

由于上述计算过程是从低位到高位的顺序产生八进制数的各个数位,而打印输出,

一般来说应从高位到低位进行,恰好和计算过程相反,

因此,若将计算过程中得到的八进制数的各个顺序进栈

则按出栈序列打印输出的即为与输入对应的八进制数

括号匹配的检验

行编辑程序问题

迷宫求解

表达式求值

  • 前缀式

  • 中缀式

  • 后缀式

    后缀式运算规则:

    • 运算符在式中出现的顺序恰为表达式的运算顺序;
    • 每个运算符和在它之前出现且紧靠它的两个操作数构成一个最小表达式。

​ 每个运算符的运算次序要由它之后的一个运算符来定,

​ 在后缀式中,优先数高的运算符领先于优先数低的运算符。

从原表达式求得后缀式的规律为:

  1. 设立运算符栈

  2. 设表达式的结束符为 “#”,预设运算符栈的栈底为 “#”

  3. 若当前字符是操作数,则直接发送给后缀式

  4. 若当前运算符的优先数高于栈顶运算符,则进栈

  5. 否者,退出栈顶运算符发送给后缀式

  6. “(” 对它之前后的运算符其隔离作用, “)” 可视为自相应左括号开始的表达

  7. 实现递归

当在一个函数的运行期间调用另一个函数时,在运行该被调用函数之前,需先完成三件事:

  • 将所有的实在参数、返回地址等信息传递给被调用函数保存。
  • 为被调用函数的局部变量分配存储区。
  • 将控制转移到被调用函数的入口。

从被调用函数返回调用函数之前,应该完成:

  • 保存被调函数的计算结果
  • 释放被调函数的数据区
  • 依照被调函数保存的返回地址将控制转移到调用函数

栈类型的实现

  • 顺序栈
  • 链栈

队列的类型定义

和栈相反,队列 是一种 先进先出,缩写为FIFO的线性表

它只允许在表的一端进行插入,而在另一端删除元素。

在队列中,允许插入的一端叫做 队尾,允许删除的一端 称为 队头

队列在程序设计中经常出现。

一个最典型的例子就是操作系统中的作业排队。

在允许多道程序运行的计算机系统中,同时有几个作业运行。

如果运行的结果都允许通过通道输出,那就要按要求输出的次序排队。

每当通道传输完毕可以接收新的输出任务时,队头的作业先从队列中退出作输出操作

凡是申请输出的作业都从队尾进入队列

线面给出队列的抽象数据类型定义

除了栈和队列之外,还有一种限定性数据结构是双端队列

双端队列是限定插入和删除操作在表的两端进行的线性表。

这两端分别称作端点1和端点2,也可以像栈一样,可以用一个贴到转轨网络来比喻双端队列

在实际使用中,还可以有输出受限的涮短队列(即一个端点只允许插入和删除,另一个端点只允许删除的双端队列)

而如果限定双端队列从某个端点插入的元素,只能从该端点删除,则该双端队列就蜕变为两个栈底相邻接的栈了

尽管双端队列看起来似乎比栈和队列更灵活,但实际上在应用程序中远不及栈和队列有用,故在此不做详细讨论

链队列-队列的链式表示和实现

和线性表类似,队列也可以有2种存储表示

用链表表示的队列加昵称为 链队列

一个链队列显然需要2个分别指示 队头 和 队尾 的指针(分别称为头指针 和 尾指针)才能惟一确定。

这里,和线性表的单链表一样,为了操作方便起见,我们也给链队列添加一个 头结点,并令 头指针 指向 头结点

由此,空的链队列的判决条件 为 头指针 和 尾指针均指向头结点

链队列的操作 即为 单链表的插入 和 删除操作的特殊情况,只是尚需修改尾指针 或 头指针,

图展示了这2中操作 进行时,指针变化的情况

线面给出 链队列类型鹅模块说明

队列头、队列尾

  • 初始化销毁操作

    • InitQueue(&Q)
    • DestroyQueue(&Q)
  • 引用型操作

    • QueueEmpty(Q)
    • QueueLength(Q)
    • GetHead(Q, &e)
  • 加工型操作

    • ClearQueue(&Q)
    • EnQueue(&Q, e)
    • DeQueue(&Q, &e)

队列类型的实现

第4章 串

串的抽象数据类型定义

串的表示和实现

串的定长顺序存储表示

串的堆分配存储表示

串的块链存储表示

串值也可用链表来存储,由于串的数据元素是一个字符,它只有8位二进制数,因此用链表存储时,通常一个结点中存放的不是一个字符,而是一个子串,

例如:在编辑系统中,整个文本编辑区可以看成一个串,每一行是一个子串,构成一个结点。

即同一行的串用定长结构(80个字符),行和行之间用指针相联接。

串的模式匹配算法

下面讨论以定长顺序结构表示串时的几种算法

  1. 简单算法(朴素算法)
int Index(SString S, SString T, int pos) {
    // 返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数值为0
    // 其中,T非空,1 <= pos <= StrLength(S)
    i = pos; j = 1;
    while (i <= s[0] && j <= T[0]) {
        if (S[i] == T[j]) {
            ++i;
            ++j;
        }
        else {
            i = i -j + 2;
            j = 1;
        }
    }
    if (j > T[0])
        return i - T[0];
    else
        return 0;
} // Index
  1. 首位匹配算法

  2. KMP算法

递归算法

第5章 数组和广义表

数组的定义

数组的顺序表示和实现

矩阵的压缩存储

特殊矩阵

稀疏矩阵

广义表的定义

广义表的存储结构

m元多项式的表示

广义表的递归算法

求广义表的深度

复制广义表

建立广义表的存储结构

第6章 树和二叉树

树的定义和基本术语

树是n(n >= 0)个结点的有限集。

在任意一颗非空树中:

1、有且仅有一个特定的称为根的结点

2、当n>1时,其余结点可分为m个互不相交的有限集T1, T2, T3… Tm,其中每一个集合本身又是一棵树,并且称为根的子树

树的结构定义是一个 递归的定义,即在树的定义中又用到树的概念,它道出了树的固有特性。

树还有其他的表示形式

其中(a)是以嵌套集合(即是一些集合的集体,对于其中任何两个集合,或者不相交,或者一个包含另一个)的形式表示的

(b)是以广义表的形式表示的,根作为由子树森林组成的表表的名字写在标的坐标

(c)是凹入表示法(类似书的编码)

树的结点包含一个数据元素及若干指向其子树的分支。结点拥有的子树数称为 结点 的 度。

度 为 0 的结点称为 叶子 或 终端 结点

度 不为 0 的结点 称为 非终端结点 或 分支结点

除根节点之外,分支结点 也称为 内部结点

树的 度 是 树内各结点 的 度 的最大值

结点 的 子树 的 根 称为 该结点 的 孩子

该结点 称为 孩子 的 双亲

二叉树

二叉树的定义

二叉树的性质

二叉树的存储结构

遍历二叉树和线索二叉树

遍历二叉树

线索二叉树

树和森林

树的存储结构

森林与二叉树的转换

树和森林的遍历

树与等价问题

赫夫曼树及其应用

最优二叉树(赫夫曼树)

赫夫曼编码

回溯法与树的遍历

树的计数

第7章 图

图的定义和术语

图的存储结构

数组表示法

邻接表

十字链表

邻接多重表

图的遍历

深度优先搜索

广度优先搜索

图的连通性问题

无向图的连通分量和生成树

有向图的强联通分量

最小生成树

关节点和重连通分量

有向无环图及其应用

拓扑排序

关键路径

最短路径

从某个源点到其余各顶点的最短路径

每一对顶点之间的最短路径

第8章 动态存储管理

概述

可利用空间表及分配方法

边界标识法

可利用空间表的结构

分配算法

回收算法

伙伴系统

可利用空间表的结构

分配算法

回收算法

无用单元收集

存储紧缩

第9章 查找

静态查找表

顺序表的查找

有序表的查找

静态树表的查找

索引顺序表的查找

动态查找表

二叉排序树和平衡二叉树

B_树和B+树

键树

哈希表

什么是哈希表

哈希函数的构造方法

处理冲突的方法

哈希表的查找及其分析

散列表查找

基于散列存储

和 线性表查找方法 完全不同

顺序, 折半

4种存储结构

顺序存储结构

链式存储结构

索引存储结构

散列存储结构

创建散列表 就是 查找三里诶包的方法

理想情况下, ASL = 1

最常用的散列函数为

储留余数发

第10章 内部排序

概述

插入排序

直接插入排序

其他插入排序

希尔排序

快速排序

选择排序

简单选择排序

树形选择排序

堆排序

对长度为n的线性表排序,在最坏情况下,比较次数不是n(n-1)/2的排序方法是 堆排序

解析:除了堆排序算法的比较次数是nlog2n, 其他都是n(n-1)/2

归并排序

基数排序(Radix Sort)

分散, 收集

稳定的排序方法

多关键字的排序

10进制的 基数 0, 1,2, …9

链队

typedef struct

用到 辅助空间

空间复杂度, 比较高

正确的思想

入队

出队

基本: 写出每一趟的结果

掌握

直接插入排序

冒泡排序

简单选择排序, 找最小值, 找到最小值, 交换

快速排序

希尔排序

归并排序

基数排序

C语言中取 每位数字的方法

%10
/10 %10
/100 %10
/1000 %10

链式基数排序

各种内部排序方法的比较讨论

直接插入排序

(1) [31 44]

希尔排序

冒泡排序

快速排序

简单选择排序

直接交换, 不后移

[6] 44 37 72 31 49
[6 31] 37 72 44 49
[6 31 37] 72 44 49
[6 31 37 44] 72 49
[6 31 37 44 49] 72

归并排序

3趟

[31, 44], [37, 72], [6, 49]
[31, 37, 44, 72], [6, 49]
[6, 31, 37, 44, 49, 72]

基数排序

2趟


第11章 外部排序

外存信息的存取

外部排序的方法

多路平衡归并的实现

置换-选择排序

最佳归并树

第12章 文件

有关文件的基本概念

顺序文件

索引文件

ISAM文件和VSAM文件

ISAM文件

VSAM文件

直接存取文件(散列文件)

多重表文件

倒排文件

多关键字文件

附录A 名词索引

附录B 函数索引

数据结构学习方法

翻书

画图 画图 画图

动手写

学习数据结构的方法

手不能懒,要经常画图

posted on 2021-06-23 23:52  beyondx  阅读(38)  评论(0编辑  收藏  举报

导航