浙江大学MOOC-数据结构-线性结构

例:多项式的表示
  • 顺序结构直接表示:
    在这里插入图片描述
    使用数组来储存系数,相应的下表就是对应项的指数

  • 顺序结构储存非零项
    使用结构数组, 其分量是 ( a i , i ) (a^i,i) (ai,i)
    按照指数的大小从大到小来排列在结构数组中,不再关心下标的作用

SUMMARY

  1. 顺序储存结构一般定义两个量:
  • int Position
  • 节点的结构指针
  1. 链式储存一般定义两个量
  • 节点的结构指针
  • 链表的结构指针
  1. 链表的结尾一定要指向NULL不然遍历链表的时候就会越界报错
  2. 链表最好有头节点,方便操作
1.线性表
1.1基本概念
  1. 定义:线性表是由同类的数据元素构成有序序列的线性结构;
  2. 长度:表中元素的个数;
  3. 空表:没有元素的线性表;
  4. 表头、表尾:表的起始和结束位置
  5. 抽象数据类型描述在这里插入图片描述
1.2 存储方法
1.2.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;   
}
1.2.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;
    }
2 广义表 General List

广义表是对线性表的推广,线性表中每个元素都得是单元素,广义表中这些元素也可以是其他广义表

typedef struct GNode *Glist;
struct GNode{
	int Tag;/*标志域,0表示union中是单元素,1表示是链表*/
	union{  /*union共用储存空间*/
		ElementType Data;
		GList SubList;
	}URegion;
	Glist Next;/*指向后继节点*/
};
3 多重链表
  1. 多重链表中的节点可能属于多个链;
  2. 节点中可能含有多个指针域,如SubList和Next
  3. 但是包含多个指针域的不一定是多重链表,如循环双向链表
例:稀疏矩阵的储存

稀疏矩阵中的零会占用很多的内存,使用十字链表储存节省空间

  1. 每个节点的数据域:行,列,值
  2. 每个节点的指针域:两个指针域把同行同列都穿起来(行列构建双向链表)
    –行指针/右指针/Right
    –列指针/左指针/Left
    在这里插入图片描述
    在这里插入图片描述

使用广义表的知识合并Head和Term节点,会发现第i行和第i列的Head节点实际上是一个节点;因为列head的left指针域与行head的right指针域没有使用,合并资源后可以看作一个

在这里插入图片描述

4 堆栈

堆栈是一种特殊的线性表,以后入先出的顺序操作其中的元素。

例:后缀表达式

计算机是如何处理我们遇到的加减乘除计算式的?
前 缀 表 达 式 : a + b ∗ c − d / e 前缀表达式:a+b*c-d/e a+bcd/e 对 应 的 后 缀 表 达 式 : a b c ∗ + d e / − 对应的后缀表达式:abc*+de/- :abc+de/
转化为对应的后缀表达式:
–遇到运算数就记住;
–遇到运算符就用最近记住的两个数进行计算。
这里就要用到堆栈的思想

4.1 堆栈的抽象数据类型描述

在这里插入图片描述
在这里插入图片描述
其中最主要的是push和pop两种操作

4.2 操作集的顺序储存实现
typedef int Position;
struct SNode {
    ElementType *Data; /* 存储元素的数组 */
    Position Top;      /* 栈顶指针 */
    int MaxSize;       /* 堆栈最大容量 */
};
typedef struct SNode *Stack;
 
Stack CreateStack( int MaxSize )
{
    Stack S = (Stack)malloc(sizeof(struct 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->Data[++(S->Top)] = X;
        return true;
    }
}
 
bool IsEmpty( Stack S )
{
    return (S->Top == -1);
}
 
ElementType Pop( Stack S )
{
    if ( IsEmpty(S) ) {
        printf("堆栈空");
        return ERROR; /* ERROR是ElementType的特殊值,标志错误 */
    }
    else 
        return ( S->Data[(S->Top)--] );
}
4.3 操作集的链式储存实现
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 )
{ /* 判断堆栈S是否为空,若是返回true;否则返回false */
    return ( S->Next == NULL );
}
 
bool Push( Stack S, ElementType X )
{ /* 将元素X压入堆栈S */
    PtrToSNode TmpCell;
 
    TmpCell = (PtrToSNode)malloc(sizeof(struct SNode));
    TmpCell->Data = X;
    TmpCell->Next = S->Next;
    S->Next = TmpCell;
    return true;
}
 
ElementType Pop( Stack S )  
{ /* 删除并返回堆栈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;
    }
}
5 队列

从一头插入,从另一头取出

5.1 队列的抽象数据类型描述

在这里插入图片描述
为了使用方便我们采用循环队列:
在这里插入图片描述
又因为循环队列在语言中实际上并没有直接的数据类型,我们使用普通的数组和链表来实现;在这里我们需要用到除法来实现循环的功能。

5.2 操作集顺序储存实现

注意在顺序储存中 front 总是指向第一个元素的前一个位置,整个数组总最多放
n-1个元素,不放满。但是链表中没有大小限制了,front 指向第一个元素的地址。

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 false;
    }
    else {
        Q->Rear = (Q->Rear+1)%Q->MaxSize;
        Q->Data[Q->Rear] = X;
        return true;
    }
}
 
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];
    }
}
5.3 操作集链式储存实现
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;
    }
}

例 多项式加法的链式实现

在这里插入图片描述
其中的 A t t a c h ( ) Attach() Attach()函数实现如下
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值