1 顺序表
1.1 顺序表的定义与操作
1.1.1 顺序表的数据结构
typedef int Position;
typedef struct LNode *List;
struct LNode {
ElementType Data[MAXSIZE];
Position Last;
};
1.1.2 顺序表的初始化
/* 初始化 */
List MakeEmpty()
{
List L;
L = (List)malloc(sizeof(struct LNode));
L->Last = -1;
return L;
}
1.1.3 顺序表的查找
/* 查找 */
#define ERROR -1
Position Find( List L, ElementType X )
{
Position i = 0;
while( i <= L->Last && L->Data[i]!= X )
i++;
if ( i > L->Last ) return ERROR; /* 如果没找到,返回错误信息 */
else return i; /* 找到后返回的是存储位置 */
}
1.1.4 顺序表的插入
/* 插入 */
/*注意:在插入位置参数P上与课程视频有所不同,课程视频中i是序列位序(从1开始),这里P是存储下标位置(从0开始),两者差1*/
bool Insert( List L, ElementType X, Position P )
{ /* 在L的指定位置P前插入一个新元素X */
Position i;
if ( L->Last == MAXSIZE-1) {
/* 表空间已满,不能插入 */
printf("表满");
return false;
}
if ( P<0 || P>L->Last+1 ) { /* 检查插入位置的合法性 */
printf("位置不合法");
return false;
}
for( i=L->Last; i>=P; i-- )
L->Data[i+1] = L->Data[i]; /* 将位置P及以后的元素顺序向后移动 */
L->Data[P] = X; /* 新元素插入 */
L->Last++; /* Last仍指向最后元素 */
return true;
}
1.1.5 顺序表的删除
/* 删除 */
/*注意:在删除位置参数P上与课程视频有所不同,课程视频中i是序列位序(从1开始),这里P是存储下标位置(从0开始),两者差1*/
bool Delete( List L, Position P )
{ /* 从L中删除指定位置P的元素 */
Position i;
if( P<0 || P>L->Last ) { /* 检查空表及删除位置的合法性 */
printf("位置%d不存在元素", P );
return false;
}
for( i=P+1; i<=L->Last; i++ )
L->Data[i-1] = L->Data[i]; /* 将位置P+1及以后的元素顺序向前移动 */
L->Last--; /* Last仍指向最后元素 */
return true;
}
1.2 链式表的定义与操作
1.2.1 链式表的数据结构
typedef struct LNode *PtrToLNode;
struct LNode {
ElementType Data;
PtrToLNode Next;
};
typedef PtrToLNode Position;
typedef PtrToLNode List;
1.2.2 链式表的查找
/* 查找 */
#define ERROR NULL
Position Find( List L, ElementType X )
{
Position p = L; /* p指向L的第1个结点 */
while ( p && p->Data!=X )
p = p->Next;
/* 下列语句可以用 return p; 替换 */
if ( p )
return p;
else
return ERROR;
}
1.2.3 链式表的插入
/* 带头结点的插入 */
/*注意:在插入位置参数P上与课程视频有所不同,课程视频中i是序列位序(从1开始),这里P是链表结点指针,在P之前插入新结点 */
bool Insert( List L, ElementType X, Position P )
{ /* 这里默认L有头结点 */
Position tmp, pre;
/* 查找P的前一个结点 */
for ( pre=L; pre&&pre->Next!=P; pre=pre->Next ) ;
if ( pre==NULL ) { /* P所指的结点不在L中 */
printf("插入位置参数错误\n");
return false;
}
else { /* 找到了P的前一个结点pre */
/* 在P前插入新结点 */
tmp = (Position)malloc(sizeof(struct LNode)); /* 申请、填装结点 */
tmp->Data = X;
tmp->Next = P;
pre->Next = tmp;
return true;
}
}
1.2.4 链式表的删除
/* 带头结点的删除 */
/*注意:在删除位置参数P上与课程视频有所不同,课程视频中i是序列位序(从1开始),这里P是拟删除结点指针 */
bool Delete( List L, Position P )
{ /* 这里默认L有头结点 */
Position pre;
/* 查找P的前一个结点 */
for ( pre=L; pre&&pre->Next!=P; pre=pre->Next ) ;
if ( pre==NULL || P==NULL) { /* P所指的结点不在L中 */
printf("删除位置参数错误\n");
return false;
}
else { /* 找到了P的前一个结点pre */
/* 将P位置的结点删除 */
pre->Next = P->Next;
free(P);
return true;
}
}
1.3 其他类型的线性表
- 广义表
- 多重链表(图的应用,稀疏矩阵会造成浪费,使用十字链表来表示稀疏矩阵)
- 双向链表
2 堆栈
-
前缀表达式
-
中缀表达式
-
后缀表达式(堆栈应用,遇到符号退两个数字)
-
插入数据:入栈(Push)
-
删除数据:出栈(Pop)
-
性质:后入先出(LIFO)
2.1 栈的顺序存储实现
栈的顺序存储结构通常由一个一维数组和一个记录栈顶元素位置的变量组成。
2.1.1 栈的数据结构
#define MaxSize <可存储的最大值>
typedef struct SNode *Stack;
struct SNode{
ElementType Data[MaxSize];
int Top;
}
2.1.2 入栈操作
void Push(Stack PtrS, ElementType item){
if(PtrS -> Top == MaxSize - 1){
printf("栈满");
return;
}else{
PtrS -> Data[++(PtrS -> Top)] = item;
}
}
2.1.3 出栈(Pop)
ElementType Pop(Stack PtrS){
if(PtrS -> Top == -1){
printf("堆栈空");
return ERROR;
}else
return (PtrS -> Data[(PtrS -> Top)--])
}
2.1.4 [例题]
请用一个数组实现两个堆栈,只要数组有剩余空间就可以进行入栈操作且成功
- 思路:栈底分别设为数组的两头,两个栈顶指针相遇时表示两个栈满
- 结构
#define MaxSize
struct DStack{
ElementType Data[MaxSize];
int Top1;
int Top2;
}S;
S.Top1 = -1;
S.Top2 = MaxSize;
2.2 栈的链式存储结构
-
数据结构
-
入栈操作
-
出栈操作
2.3 堆栈的其他应用
- 函数调用及递归实现
- 深度优先搜索
- 回溯算法
#队列
2.4 应用实例1 —— 多项式加法运算
采用不带头结点的单向链表,按照指数递减的顺序排列各项
2.5 应用实例2 —— 一元多项式的乘积与和
设计函数分别求两个一元多项式的乘积与和
已知两个多项式
(1) 3x^4 - 5x^2 + 6x - 2
(2) 5x^20 - 7x^4 + 3x
输入样例:
4 3 4 -5 2 6 1 -2 0
3 5 20 -7 4 3 1
输出样例
15 24 -25 22 30 21 -10 20 -21 8 35 6 -33 5 14 4 -15 3 18 2 -6 1
5 20 -4 4 -5 2 9 1 -2 0
2.5.1 求解思路
- 多项式表示
- 程序框架
- 读多项式
- 加法实现
- 乘法实现
- 多项式输出
2.5.2 多项式表示
1.1 数组:
编程简单、调试容易
但要事先确定数组大小
1.2 链表
动态性强
编程略微复杂、测试比较困难
(一种比较好的实现方法是:动态数组)
数据结构设计
typedef s
2.5.3 程序框架
基础框架:
int main(){
读入多项式1
读入多项式2
乘法运算并输出
加法运算并输出
return 0;
}
可以知道需要设计的函数:
- 读一个多项式
- 两个多项式相乘
- 两个多项式相加
- 多项式输出
将需求改写成函数描述:
int main(){
Polynomial P1, P2, PP, PS;
P1 = ReadPoly();
P2 = ReadPoly();
PP = Mult(P1, P2);
PrintPoly(PP);
PS = Add(P1, P2);
PrintPoly(PS);
return 0;
}
2.5.4 读多项式
3.1 读多项式框架
Polynomial ReadPoly(){
...
scanf("%d", &N);
...
while(N--){
scanf("%d %d", &c, &e);
Attach(c, e, &Rear); //构建的作用:将输入的ce插入链表尾部
}
...
return P;
}
Rear的初值处理方法:
1.Rear的初值为NULL
在Attach函数中根据Rear是否为NULL做不同的处理
(需要判断Rear是否为NULL)
2.Rear指向一个空结点
一致性较强,但最后要删除
3.2 Attach()函数:读入数据插入链表尾部
void Attach(int c, int e, Polynomial *pRear){
Polynomial P;
P = (Polynomial)malloc(sizeof(struct PolyNode));
P -> coef = x; //对新结点赋值
P -> expon = e;
P -> link = NULL;
(*pRear) -> link = P; //把新申请的P放进pRear的后面
*pRear = P; //修改pRear的值
}
3.3 完整框架
2.5.5 多项式相加
2.5.6 多项式相乘
方法
-
将乘法运算转换成加法运算
将P1当前项(ci, ei)乘P2多项式,再加到结果多项式里 -
逐项插入