【数据结构】1.线性结构

此笔记根据中国大学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:链表结构存储非零项
结点:
在这里插入图片描述
例如:
在这里插入图片描述
链表表示为:
在这里插入图片描述
从上述多项式问题中得到启示

  1. 同一个问题可以有不同的表示(存储)方法
  2. 有一类共性问题:有序线性序列的组织和管理

在这里插入图片描述

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两个指针域;
但包含两个指针域的链表并不一定是多重链表,比如双向链表不是多重链表。

√ 只存储矩阵非0元素项结点的数据域:行坐标Row、列坐标Col、数值Value√ 每个结点通过两个指针域,把同行、同列串起来; 行指针(或称为向右指针)Right 列指针(或称为向下指针)Down

在这里插入图片描述

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以及 更多有意思的 分享,可搜一搜 微信公共号 “分享猿” 免费获取资源。也可扫描下面的二维码关注,期待你的到来~
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值