此笔记根据中国大学MOOC上浙江大学《数据结构》课件整理
视频地址: https://www.icourse163.org/learn/ZJU-93001?tid=1003997005#/learn/announce
主讲: 陈越、何钦铭
资源下载: 相关课件PPT,数据结构教材pdf,以及此数据结构笔记(包括word版,pdf版,以及MarkDown版本), 可以关注我的公众号“分享猿”,回复关键词“N01”获取资源!
本节思维导图
使用软件:XMind8
2.1 线性表的引入
[例] 对于一元多项式:(多项式项数n; 各项系数ai 及指数 i)
方法1:顺序存储结构直接表示
例如:
表示成:
优点:运算方便,两多项式相加可对应下标系数相加;
缺点:如表示 将造成空间的巨大浪费。
方法2:顺序存储结构表示非零项
将每个多项式看作为(ai,i) 二元组储存
用结构数组表示:
和
为
备注:需要按指数大小有序存储!
相加过程:从头开始,比较两个多项式当前对应项的指数
P1: (9,12), (15,8), (3,2)
P2: (26,19), (-4,8), (-13,6), (82,0)
↓
P3: (26,19) (9,12) (11,8) (-13,6) (3,2) (82,0)
即:
方法3:链表结构存储非零项
例如:
链表表示为:
从上述多项式问题中得到启示:
- 同一个问题可以有不同的表示(存储)方法
- 有一类共性问题:有序线性序列的组织和管理
2.2线性表的顺序存储实现
☆主要操作的实现
- 初始化(建立空的顺序表)
List MakeEmpty( )
{ List PtrL;
PtrL = (List )malloc( sizeof(struct LNode) );
ptrL->Last = -1;
return PtrL;
}
- 查找
int Find( ElementType X, List PtrL )
{ int i = 0;
while( i <= PtrL->Last && PtrL->Data[i]!= X )
i++;
if (i > PtrL->Last) return -1; /* 如果没找到,返回-1 */
else return i; /* 找到后返回的是存储位置 */
}
- 插入
void Insert( ElementType X, int i, List PtrL )
{ int j;
if ( PtrL->Last == MAXSIZE-1 ){ /* 表空间已满,不能插入*/
printf("表满");
return;
}
if ( i < 1 || i > PtrL->Last+2) { /*检查插入位置的合法性*/
printf("位置不合法");
return;
}
for ( j = PtrL->Last; j >= i-1; j-- )
PtrL->Data[j+1] = PtrL->Data[j]; /*将 ai~ an倒序向后移动*/
PtrL->Data[i-1] = X; /*新元素插入*/
PtrL->Last++; /*Last仍指向最后元素*/
return;
}
- 删除
void Delete( int i, List PtrL )
{ int j;
if ( i < 1 || i > PtrL->Last+1 ) { /*检查空表及删除位置的合法性*/
printf ("不存在第%d个元素", i );
return ;
}
for ( j = i; j <= PtrL->Last; j++ )
PtrL->Data[j-1] = PtrL->Data[j]; /*将 ai+1~ an顺序向前移动*/
PtrL->Last--; /*Last仍指向最后元素*/
return;
}
2.3线性表的链式存储实现
typedef struct LNode *List;
struct LNode{
ElementType Data;
List Next;
};
struct Lnode L;
List PtrL;
☆主要操作的实现
- 求表长
int Length ( List PtrL )
{ List p = PtrL; /* p指向表的第一个结点*/
int j = 0;
while ( p ) {
p = p->Next;
j++; /* 当前p指向的是第 j 个结点*/
}
return j;
}
- 查找
- 按序号查找: FindKth;
List FindKth( int K, List PtrL )
{ List p = PtrL;
int i = 1;
while (p !=NULL && i < K ){
p = p->Next;
i++;
}
if ( i == K ) return p; /* 找到第K个,返回指针 */
else return NULL; /* 否则返回空 */
}
- 按值查找: Find
List Find( ElementType X, List PtrL )
{
List p = PtrL;
while ( p!=NULL && p->Data != X )
p = p->Next;
return p;
}
- 插入
List Insert( ElementType X, int i, List PtrL )
{ List p, s;
if ( i == 1 ) { /* 新结点插入在表头 */
s = (List)malloc(sizeof(struct LNode)); /*申请、填装结点*/
s->Data = X;
s->Next = PtrL;
return s; /*返回新表头指针*/
}
p = FindKth( i-1, PtrL ); /* 查找第i-1个结点 */
if ( p == NULL ) { /* 第i-1个不存在,不能插入 */
printf("参数i错");
return NULL;
}else {
s = (List)malloc(sizeof(struct LNode)); /*申请、填装结点*/
s->Data = X;
s->Next = p->Next; /*新结点插入在第i-1个结点的后面*/ p->Next = s;
return PtrL;
}
}
- 删除
List Delete( int i, List PtrL )
{ List p, s;
if ( i == 1 ) { /* 若要删除的是表的第一个结点 */
s = PtrL; /*s指向第1个结点*/
if (PtrL!=NULL) PtrL = PtrL->Next; /*从链表中删除*/
else return NULL;
free(s); /*释放被删除结点 */
return PtrL;
}
p = FindKth( i-1, PtrL ); /*查找第i-1个结点*/
if ( p == NULL ) {
printf("第%d个结点不存在", i-1); return NULL;
} else if ( p->Next == NULL ){
printf("第%d个结点不存在", i); return NULL;
} else {
s = p->Next; /*s指向第i个结点*/
p->Next = s->Next; /*从链表中删除*/
free(s); /*释放被删除结点 */
return PtrL;
}
}
2.4广义表
Generalized List:
广义表是线性表的推广;
对于线性表而言,n个元素都是基本的氮元素;
广义表中,这些元素不仅可以是单元素也可以是另一个广义表。
如二元多项式:
可看做一元多项式
即:
2.5 多重链表
广义表是多重链表的一种类型
一种典型多重链表 – 十字链表(如存储稀疏矩阵)
多重链表:链表中的结点可能同时隶属于多个链
多重链表中结点的指针域会有多个,如前面例子包含了Next和SubList两个指针域;
但包含两个指针域的链表并不一定是多重链表,比如双向链表不是多重链表。
2.6 堆栈 - 后入先出
2.6.1 定义
中缀表达式:6/2-3+4*2 = 8
后缀表达式:6 2 /3 -4 2 * + = 8
后缀求值策略 – 从左往右”扫描”,逐个处理运算数和运算符号
1.遇到数 – “记住”;
2.遇到符号 – 将最近的两个数作相应运算。
上面后缀表达式的堆栈过程
启示 - 需要一种存储方法,能顺序存数,并能倒序读出。
堆栈(Stack):
具有一定操作约束的线性表
只在一端(栈顶,Top)做 插入、删除
2.6.2栈的顺序存储实现
一个一维数组
一个记录栈顶元素位置的变量
#define MaxSize <储存数据元素的最大个数>
typedef struct SNode *Stack;
struct SNode{
ElementType Data[MaxSize];
int Top;
};
- 入栈
void Push( Stack PtrS, ElementType item )
{
if ( PtrS->Top == MaxSize-1 ) {
printf("堆栈满"); return;
}else {
PtrS->Data[++(PtrS->Top)] = item;
return;
}
}
- 出栈
ElementType Pop( Stack PtrS )
{
if ( PtrS->Top == -1 ) {
printf("堆栈空");
return ERROR; /* ERROR是ElementType的特殊值,标志错误*/
} else
return ( PtrS->Data[(PtrS->Top)--] );
}
2.6.3 堆栈的链式存储实现
typedef struct SNode *Stack;
struct SNode{
ElementType Data;
struct SNode *Next;
} ;
- 堆栈初始化(建立空栈)
Stack CreateStack()
{ /* 构建一个堆栈的头结点,返回指针 */
Stack S;
S =(Stack)malloc(sizeof(struct SNode));
S->Next = NULL;
return S;
}
- 判断堆栈是否为空
int IsEmpty(Stack S)
{ /*判断堆栈S是否为空, 若为空函数返回整数1, 否则返回0 */
return ( S->Next == NULL );
}
- 入栈
void Push( ElementType item, Stack S)
{ /* 将元素item压入堆栈S */
struct SNode *TmpCell;
TmpCell=(struct SNode *)malloc(sizeof(struct SNode));
TmpCell->Element = item;
TmpCell->Next = S->Next;
S->Next = TmpCell;
}
- 出栈
ElementType Pop(Stack S)
{ /* 删除并返回堆栈S的栈顶元素 */
struct SNode *FirstCell;
ElementType TopElem;
if ( IsEmpty( S ) ) {
printf("堆栈空"); return NULL;
} else {
FirstCell = S->Next;
S->Next = FirstCell->Next;
TopElem = FirstCell ->Element;
free(FirstCell);
return TopElem;
}
}
2.7 队列 – 先进先出
2.7.1定义
Queue
具有一定操作的线性表
插入和删除操作:只能在一端插入,另一端删除
2.7.2队列的顺序存储实现
一个一维数组;
一个记录队列头元素位置的变量front;
一个记录队列尾元素位置的变量rear。
在这里插入代码片#define MaxSize <储存数据元素的最大个数>
struct QNode {
ElementType Data[ MaxSize ];
int rear;
int front;
};
typedef struct QNode *Queue;
为了不造成空间浪费,可以继续在0、1位置添加,这样就形成了一个顺环队列
此时Front=Rear=0
假如:
此时继续添加一个数 到队列中时,有Front=Rear=1,此时便会产生歧义:Front=Rear时,队列时满还是空?
原因:
这种方法使用Rear与Front之间的距离来体现队列情况,但Rear-Front有0,1,2,3,4,5,共六种情况,而队列中元素占据的空间有0~6共7种可能,用6种情况表示7种,当然不能满足。
解决方案:
√ 使用额外标记:Size或者Tag域;
√ 仅使用n-1个数组空间。
*下列以上面第二种解决方案为基础
- 入队列
void AddQ( Queue PtrQ, ElementType item)
{
if ( (PtrQ->rear+1) % MaxSize == PtrQ->front ) {
printf(“队列满”);
return;
}
PtrQ->rear = (PtrQ->rear+1)% MaxSize;
PtrQ->Data[PtrQ->rear] = item;
}
- 出队列
ElementType DeleteQ ( Queue PtrQ )
{
if ( PtrQ->front == PtrQ->rear ) {
printf(“队列空”);
return ERROR;
} else {
PtrQ->front = (PtrQ->front+1)% MaxSize;
return PtrQ->Data[PtrQ->front];
}
}
* n % Maxsize 的循环使用
2.7.3队列的链式存储实现
struct Node{
ElementType Data;
struct Node *Next;
};
struct QNode{ /* 链队列结构 */
struct Node *rear; /* 指向队尾结点 */
struct Node *front; /* 指向队头结点 */
};
typedef struct QNode *Queue;
Queue PtrQ;
不带头结点的链式队列出队操作的一个示例
ElementType DeleteQ ( Queue PtrQ )
{ struct Node *FrontCell;
ElementType FrontElem;
if ( PtrQ->front == NULL) {
printf(“队列空”); return ERROR;
}
FrontCell = PtrQ->front;
if ( PtrQ->front == PtrQ->rear) /* 若队列只有一个元素 */
PtrQ->front = PtrQ->rear = NULL; /* 删除后队列置为空 */
else
PtrQ->front = PtrQ->front->Next;
FrontElem = FrontCell->Data;
free( FrontCell ); /* 释放被删除结点空间 */
return FrontElem;
}
- 创建队列
void CreatQ(Queue PrtQ,ElementType item)
{
PtrQ→Front = PtrQ→Rear = (Qnode *)malloc(sizeof(struct Node));
Queue→Front→Next = NULL;
}
- 入队列
void AddQ(Queue Q,ElementType item)
{
P = (Queue )malloc(sizeof(struct Node));
P → Next = NULL;
P → Data = item;
if (Q→Front = NULL):
Q→Front = Q→Rear=Next;
else{
Q→Rear→Next = P
Q→Rear = P;
}
return ;
}
获取本文word版数据结构笔记,以及数据结构 陈越版和严蔚敏版 PDF书籍,可在公众号“分享猿”中回复关键词 N01获取。
若要获取更多数字图像处理,python,深度学习,机器学习,计算机视觉等高清PDF以及 更多有意思的 分享,可搜一搜 微信公共号 “分享猿” 免费获取资源。也可扫描下面的二维码关注,期待你的到来~