浙大2020年Mooc数据结构笔记–第二讲线性结构
〇、前言
- 这几天开始跟着学数据结构,鉴于当初数据结构实在学的太弱,加之这项工作算是为大家之后复习、机试铺路。确实是一个迫切需要做的大规模工作。行胜于言,虽然从第二篇开始,坚持下去。
- 此文部分为自己写,部分参考网上内容。提前说一下哈。期待批评指正。
一、线性表
线性表(Linear List):由同类型数据元素构成有序序列的线性结构
线性表的相关操作:
List MakeEmpty():初始化一个空线性表L;
ElementType FindKth( int K, List L ):根据位序K,返回相应元素 ;
int Find( ElementType X, List L ):在线性表L中查找X的第一次出现位置;
void Insert( ElementType X, int i, List L):在位序i前插入一个新元素X;
void Delete( int i, List L ):删除指定位序i的元素;
int Length( List L ):返回线性表L的长度n。
1、线性表的顺序存储实现
typedef int Position;
typedef struct LNode *List;
struct LNode {
ElementType Data[MAXSIZE];
Position Last;
};
/* 初始化 */
List MakeEmpty()
{
List L;
L = (List)malloc(sizeof(struct LNode));
L->Last = -1;
return L;
}
/* 查找 */
#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; /* 找到后返回的是存储位置 */
}
/* 插入 */
/*注意:在插入位置参数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;
}
/* 删除 */
/*注意:在删除位置参数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;
}
2、线性表的链式存储实现
typedef struct LNode *PtrToLNode;
struct LNode {
ElementType Data;
PtrToLNode Next;
};
typedef PtrToLNode Position;
typedef PtrToLNode List;
/* 查找 */
#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;
}
/* 带头结点的插入 */
/*注意:在插入位置参数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;
}
}
/* 带头结点的删除 */
/*注意:在删除位置参数P上与课程视频有所不同,
课程视频中i是序列位序(从1开始),这里P是拟删除结点指针 */
bool Delete( List L, Position P )
{ /* 这里默认L有头结点 */
Position tmp, 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;
}
}
二、堆栈
- 堆栈是一个特殊的线性结构
- “后入先出”的特点,只能在一端做插入,删除
- 堆栈相关操作:
Stack CreateStack(int MaxSize ):初始化空堆栈;
int isFull(Stack S,int MaxSize ):判断堆栈S是否已满;
void Push(Stack S,ElementType item):将元素item压入堆栈;
int IsEmpty(Stack S ): 判断堆栈S是否为空;
ElementType Pop(Stack S):删除并返回栈顶元素
1、堆栈的定义与操作,顺序存储实现
#include<iostream>
using namespace std;
typedef int Position;
struct SNode{
ElementType *Data; //存储元素数组
Position Top; //栈顶指针
int MaxSize; // 堆栈的最大容量
};
typedef struct SNode *Stack;
//初始化
Stack CreateStack(int MaxSize){
Stack S = (Stack)malloc(sizeof(struck SNode));
S->Data = (ElementType *)malloc(MaxSize *sizeof(ElementType))
S->Top = -1;
S->MaxSize = MaxSize;
return S;
}
//是否为满
bool isfull(Stack S){
return (S->Top == S->MaxSize-1);
}
//入栈
bool Push( Stack S,ElementType X){
if(isFull(S)){
printf("堆栈满");
return false;
}else{
S->Top++;
S->Data[S->Top] = X;
return true;
}
}
//是否为空
bool isEmpty(Stack S){
return (S->Top == -1);
}
//入栈
ElementType Pop(Stack S){
if(isEmpty(S)){
printf("堆栈空");
return ERROR;
}else {
return (S->Data[(S->Top)--]);
}
}
2、堆栈的定义与操作,链式存储实现
typedef struct SNode *PtrToSNode
struct SNode{
ElementType Data;
PtrToSNode Next;
};
typedef PtrToSNode Stack;
Stack CreateStack(){
//创建一个堆栈的头节点,返回该结点指针
Stack S;
S = (Stack)malloc(sizeof(struct SNode));
S -> next = NULL;
return S;
}
bool IsEmpty(Stack S){
return (S->Next == NULL);
}
//将元素压入堆栈S
bool Push(Stack S,ElementType X){
PtrToSNode TmpCell;
TmpCell = (PtrToSNode)malloc(sizeof(struct SNode));
TmpCell ->Data = X;
TmpCell ->Next = S ->Next;
S->Next = TmpCell;
return true;
}
//使栈顶元素出栈
ElementType Pop(Stack S){
PtrToSNode FirstCell;
ElementType TopElem;
if(IsEmpty(S)){
printf("堆栈为空");
return ERROR;
}else{
FirstCell = S -> Next;
TopElem = FirstCell -> Data;
S->Next = FirstCell -> Next;
free(FirstCell);
return TopElem;
}
}
三、队列
- 队列的特点为“先进先出”;
- 队列的相关操作:
Queue CreatQueue( int MaxSize ):生成长度为MaxSize的空队列;
int IsFullQ( Queue Q, int MaxSize ):判断队列Q是否已满;
void AddQ( Queue Q, ElementType item ):将数据item插入队列Q中;
int IsEmptyQ( Queue Q ): 判断队列Q是否为空;
ElementType DeleteQ( Queue Q ):将队头数据从队列中删除并返回。
1、队列的定义与操作,顺序存储实现
typedef int Position;
struct QNode{
ElementType *Data;
Position Front,Rear;
int MaxSize;
};
typedef struct QNode *Queue;
Queue CreateQueue(int MaxSize){
Queue Q = (Queue)malloc(sizeof(struct QNode));
Q->Data = (ElementType *)malloc(MaxSize *sizeof(ElementType));
Q->Front = Q->Rear = 0;
Q->MaxSize = MaxSize;
return Q;
}
bool IsFull(Queue Q){
return ((Q->Rear+1)%Q ->MaxSize == Q->Front);
}
bool AddQ(Queue Q,ElementType X){
if(IsFull(Q)){
printf("队列满");
return ERROR;
}else{
Q->Rear = (Q->Rear +1)%Q->MaxSize;
Q->Data[Q->Rear] = X;
}
}
bool IsEmpty(Queue Q){
return (Q->Front == Q->Rear);
}
ElementType DeleteQ(Queue Q){
if(IsEmpty(Q)){
printf("队列空");
return ERROR;
}else {
Q->Front = (Q->Front+1)%Q->MaxSize;
return Q->Data[Q->Front];
}
}
2、队列的定义与操作,链式存储实现
typedef struct Node *PtrToNode;
struct Node { /* 队列中的结点 */
ElementType Data;
PtrToNode Next;
};
typedef PtrToNode Position;
struct QNode {
Position Front, Rear; /* 队列的头、尾指针 */
int MaxSize; /* 队列最大容量 */
};
typedef struct QNode *Queue;
bool IsEmpty( Queue Q )
{
return ( Q->Front == NULL);
}
ElementType DeleteQ( Queue Q )
{
Position FrontCell;
ElementType FrontElem;
if ( IsEmpty(Q) ) {
printf("队列空");
return ERROR;
}
else {
FrontCell = Q->Front;
if ( Q->Front == Q->Rear ) /* 若队列只有一个元素 */
Q->Front = Q->Rear = NULL; /* 删除后队列置为空 */
else
Q->Front = Q->Front->Next;
FrontElem = FrontCell->Data;
free( FrontCell ); /* 释放被删除结点空间 */
return FrontElem;
}
}
四、一元多项式的加法与乘法
具体代码实现在实验题第二题
五、课后题
1、02-线性结构1 两个有序链表序列的合并 (15分)
#include<stdlib.h>
#include<iostream>
using namespace std;
typedef struct node *ptrNode;
typedef ptrNode LinkList; //头结点
typedef ptrNode Position;//中间节点
typedef int ElementType;
struct node{
ElementType Element;
Position next;
};
int IsEmpty(LinkList L)
{
return L->next == NULL;
}
LinkList creatList(void)
{
LinkList head,r,p;
int x;
head = (struct node*)malloc(sizeof(struct node)); //生成新结点
r = head;
scanf("%d",&x);
while(x != -1){
p = (struct node*)malloc(sizeof(struct node));
p->Element = x;
r->next = p;
r = p;
scanf("%d",&x);
}
r->next = NULL;
return head;
}
LinkList mergeList(LinkList a, LinkList b)
{
Position ha, hb,hc;
LinkList c,r,p;
ha = a->next;
hb = b->next;
c = (struct node*)malloc(sizeof(struct node));
r = c;
while((ha != NULL)&&(hb != NULL)){
p = (struct node*)malloc(sizeof(struct node));
if(ha->Element <= hb->Element){
p->Element = ha->Element;
ha = ha->next;
}
else{
p->Element = hb->Element;
hb = hb->next;
}
r->next = p;
r = p;
}
if(ha == NULL){
while(hb != NULL){
p = (struct node*)malloc(sizeof(struct node));
p->Element = hb->Element;
hb = hb->next;
r->next = p;
r = p;
}
}
if(hb == NULL){
while(ha != NULL){
p = (struct node*)malloc(sizeof(struct node));
p->Element = ha->Element;
ha = ha->next;
r->next = p;
r = p;
}
}
r->next = NULL;
return c;
}
void printList(LinkList L)
{
LinkList hc;
int flag = 0;
hc = L->next;
if(hc == NULL)
printf("NULL");
while(hc != NULL){
if(flag)
printf(" ");
else
flag = 1;
printf("%d",hc->Element);
hc = hc->next;
}
}
int main(void)
{
LinkList L1,L2,L3;
L1 = creatList();
L2 = creatList();
L3 = mergeList(L1,L2);
printList(L3);
return 0;
}
输入测试:
1 2 3 -1
4 5 9 -1
输出结果:
1 2 3 4 5 9
02-线性结构2 一元多项式的乘法与加法运算(20分)
#include<stdio.h>
#include<stdlib.h>
typedef struct PolyNode *Polynomial; //多项式链指针
struct PolyNode{
int coef; //系数
int expon; //指数
Polynomial link; //链指针
};
//将某项链接到结果上
void Attach(int c,int e,Polynomial *pRear){
Polynomial P;
P=(Polynomial)malloc(sizeof(struct PolyNode));
P->coef=c;
P->expon=e;
P->link=NULL;
(*pRear)->link=P;
*pRear=P;
}
//读取多项式
Polynomial ReadPoly(){
Polynomial P,Rear,t;
int c,e,N;
scanf("%d",&N);
P=(Polynomial)malloc(sizeof(struct PolyNode));
P->link=NULL;
Rear=P;
while(N--){
scanf("%d %d",&c,&e);
Attach(c,e,&Rear);
}
t=P; P=P->link; free(t);
return P;
}
//多项式相加过程
Polynomial Mult(Polynomial P1, Polynomial P2){
Polynomial t1,t2,P,Rear,t;
int e,c;
if(!P1||!P2) return NULL; //如果两个多项式有空,则返回NULL
t1 = P1; t2 = P2;
P = (Polynomial)malloc(sizeof(struct PolyNode));
P->link = NULL; //创建结果多项式,最后要返回的值
//t1指向P1,t2指向P2,Rear指向P
Rear=P;
while(t2){
Attach(t1->coef*t2->coef,t1->expon+t2->expon,&Rear);
t2 = t2->link;
}
t1 = t1->link;
while(t1){
Rear = P;
t2 = P2;
while(t2){
c = t1->coef*t2->coef;
e = t1->expon+t2->expon;
while(Rear->link&&Rear->link->expon>e)
Rear=Rear->link;
if(Rear->link &&Rear->link->expon==e){
if(Rear->link->coef+c)
Rear->link->coef+=c;
else{
t = Rear->link;
Rear->link = t->link;
free(t);
}
}
else{
t = (Polynomial)malloc(sizeof(struct PolyNode));
t->coef = c;
t->expon=e;
t->link = Rear->link;
Rear->link =t;
Rear = Rear->link;
}
t2 = t2->link;
}
t1 = t1->link;
}
t = P; P = P->link; free(t);
return P;
}
Polynomial Add(Polynomial P1, Polynomial P2){
Polynomial t1,t2,P,Rear,t;
int e,c;
if(!P1&&!P2) return NULL;
t1 = P1;
t2 = P2;
P=(Polynomial)malloc(sizeof(struct PolyNode));
Rear = P;
while(t1&&t2){
if(t1->expon==t2->expon){
if(t1->coef!=-(t2->coef))
Attach(t1->coef+t2->coef, t1->expon, &Rear);
t1 = t1->link;
t2 = t2->link;
}
else if(t1->expon>t2->expon){
Attach(t1->coef, t1->expon, &Rear);
t1 = t1->link;
}
else {
Attach(t2->coef, t2->expon, &Rear);
t2 = t2->link;
}
}
Rear->link = t1 ? t1 : t2;
t = P; P = P->link; free(t);
return P;
}
//打印多项式
void PrintPoly(Polynomial P){
int flag=0;
if(!P){
printf("0 0\n");
return;
}
while(P){
if(!flag)
flag=1;
else
printf(" ");
printf("%d %d",P->coef,P->expon);
P=P->link;
}
printf("\n");
}
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;
}
输入样例:
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
3、02-线性结构3 Reversing Linked List (25分)
Sample Input:
00100 6 4
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218
Sample Output:
00000 4 33218
33218 3 12309
12309 2 00100
00100 1 99999
99999 5 68237
68237 6 -1
这题开始都看不懂题意,后来看懂,根据对比输入样例贺输出样例,灵感乍现。第一行的00100 是链表第一个元素的位置,6的意思是共有6个元素,4的意思是每4个节点反转一次。下面的6行,例如第一行:00000的位置存放的是4,4的下一个节点位置在12309.之后同理。输出也是一样的。通过开辟大规模数组即可解决问题。
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 100005
int main(){
int Data[MaxSize]; // 存放数据
int Next[MaxSize]; //存放相邻关系
int List[MaxSize];
int FirstAdd,N,K;
scanf("%d %d %d",&FirstAdd,&N,&K);
int i,j;
for(i=0;i<N;i++){
int tAdd,tData,tNext;
scanf("%d %d %d",&tAdd,&tData,&tNext);
Data[tAdd]=tData;
Next[tAdd]=tNext;
}
int sum=0;
while(FirstAdd!=-1){
List[sum++]=FirstAdd;
FirstAdd=Next[FirstAdd]; //此时List里面按顺序存放着反转前的各数字位置
}
for(i=0;i<sum-sum%K;i+=K){
for(j=0;j<K/2;j++){
int t=List[i+j]; //对List内的位置进行反转即可
List[i+j]=List[i+K-j-1];
List[i+K-j-1]=t;
}
}
for(i=0;i<sum-1;i++){
printf("%05d %d %05d\n",List[i],Data[List[i]],List[i+1]);
}
printf("%05d %d -1\n",List[i],Data[List[sum-1]]);
return 0;
}
4、02-线性结构4 Pop Sequence (25分)
Sample Input:
5 7 5
1 2 3 4 5 6 7
3 2 1 7 5 6 4
7 6 5 4 3 2 1
5 6 4 3 7 2 1
1 7 6 5 4 3 2
Sample Output:
YES
NO
NO
YES
NO
#include <stdio.h>
#include <stdlib.h>
typedef struct SNode *Stack;
struct SNode{
int data[1010];
int top;
};
void push(Stack ptrl,int a);
void pop(Stack ptrl);
int main(){
Stack ptrl;
ptrl=(Stack)malloc(sizeof(struct SNode));
// ptrl->top=-1;
int m,n,k,i,j;
scanf("%d %d %d",&m,&n,&k);
int b[1010];
while(k--){
ptrl->top=-1;
j=0;
for(i=0;i<n;i++){
scanf("%d",&b[i]);
}
for(i=1;i<=n;i++){
push(ptrl,i);
if(ptrl->top >= m){
break;
}
while(ptrl->top!=-1&&ptrl->data[ptrl->top]==b[j]){
j++;
pop(ptrl);
}
}
if (ptrl->top == -1) {
printf("YES\n");
}
else {
printf("NO\n");
}
}
}
void push(Stack ptrl,int a){
ptrl->data[++(ptrl->top)]=a;
}
void pop(Stack ptrl){
ptrl->top--;
}