【线性结构】--2.1线性表及其实现

线性表是数据结构中最基础的一种数据结构类型。

2.1.1引子:多项式表示

问题1:如何用程序设计语言表示多项式?


分析:多项式中关键数据——项数n(有几项)、各项系数ai、x的指数。

重点是表示多项式的每一项


方法1:顺序存储结构直接表示


分析:

多项式的每一项系数ai放在数组中,即 a[i]存储,同时x的指数为i

即创建数组a,按指数顺序存储各项系数。

如:f(x)=

下标i

0

1

2

3

4

5

a[i]

1

0

-3

0

0

4

x

优点:两个多项式相加简单,直接两个数组对应分量相加即可。

缺点:多项式较空(非零项很少)时,很浪费存储空间。


经过思考改进,可以得到第二种方法。

※方法2:顺序存储结构表示非零项


分析:

把多项式看成是一个(,i)的集合。

结构数组表示:数组的分量由系数指数i组成。

如:f(x)=

数组下标

0

1

2

……

系数

4

-3

1

……

指数i

5

2

0

……

要点:按指数大小有序存储❗

相加过程:从头开始,比较两个多项式当前对应项的指数。

P1:(9,12), (15,8), (3,2)

P2:(26,19), (-4,8), (-13,6),(82,0)

P3:(26,19),(9,12), (15-4,8), (-13,6),(3,2),(82,0)

这种方法节省空间并且操作效率也不错。


同时,表示非零项还可以用链表的方式。

※方法3:链表结构存储非零项


分析:在这个链表里,每个节点包含两个信息,系数指数i;用指针域把不同的项串起来。

要点:按指数大小有序存储❗

如:

P1:(9,12), (15,8), (3,2)

P2:(26,19), (-4,8), (-13,6),(82,0)

表示为:

相加过程:从头开始,比较两个多项式当前对应项的指数。


小归纳:多项式的问题

2.1.2线性表及顺序存储

由很多问题跟多项式问题存在共性,我们的目标是想管理一个有序的线性序列,把它归结为“线性表”问题。

线性表Linear List:由同类型数据元素构成有序序列的线性结构。

ADT线性表的抽象数据类型描述:

存储实现

  1. 线性表的顺序存储实现

利用数组的连续存储空间顺序存放线性表各元素。

定义
typedef struct LNode* List;
struct LNode{
    ElementType Data[MAXSIZE];
    int Last;
};

struct LNode L;
List PtrL;

访问下标为i的元素:

L.Data[i]
PtrL->Data[i]

线性表长度:

L.Last+1
PtrL->Last+1

主要操作
  1. 初始化(建立空的顺序表)
List MakeEmpty()
{
    List PtrL;
    PtrL=(List)malloc(sizeof(struct LNode));
    PtrL->Last=-1;
    return PtrL;
}
2.查找
int Find(ElementType X,List PtrL)
{
    int i=0;
    while(i<=PtrL->Last&&X!=PtrL->Data[i])//循环条件:没找到且未溢出数组
    {
        i++;
    }
    if(i>PtrL->Last) return -1;
    else return i;
}
3.插入(插到线性表的i位置上)i∈[1,n+1] (n是元素个数)

线性表长度为:

L.Last+1

PtrL->Last+1

//Last指向的是数组下标

这里P是存储下标位置(从0开始)

i=n+1时就插在线性表的最后

参考:(4条消息) 顺序存储结构的插入与删除_Uncertainty!!的博客-CSDN博客_顺序储存的插入与删除


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; 
} 
4.删除

这里P是存储下标位置(从0开始)

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. 线性表的链式存储

定义

不要求物理上相邻,把逻辑上相邻的两个元素通过连接在一起。

创建:

typedef struct LNode* List;
struct LNode{
    ElemnetType Data;
    List Next;
}; 

struct LNode L;
List PtrL;


思考:在一个链表中,我们只知道链表的头,如何查找第i个元素?如何知道链表的长度?

这比顺序存储结构中要复杂的多。


主要操作及实现
  1. 求表长
int Length(List PtrL)//PtrL为头指针
{
    List P=PtrL;
    int j=0;
    while(P)//当P不为空
    {
        P=P->Next;
        j++;
    }
    return j;
}

//自己又想了一下
int Length(List PtrL)//PtrL为头指针
{
    List P=PtrL;
    int j=1;
    while(P->Next)//当P不为空
    {
        P=P->Next;
        j++;
    }
    return j;
}
2.查找

(1)按序号查找

List FindKth(int K,List PtrL)
{
    List p=PtrL;
    int i=1;
    for(i=1;p!=NUll;i++)
    {
        if(i==K)
        {
            return p;
        }
        p=p->Next;
    }
    return NULL;
}

(2)按值查找

List Find(ElementType X,List PtrL)
{
    List p=PtrL;
    for(p=PtrL;p!=NULL;p=p->next)
    {
        if(p->Data==X)
        {
            return p;
        }
    }
    return NULL;
}

3.插入(在第i-1个节点后插入一个值为X的新节点)

(1)先构造一个新节点,用s指向

(2)再找到链表的第i-1个节点,用p指向

(3)修改指针,插入节点


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)//参数错误,插入失败 
    {
        printf("参数错");
        return NULL; 
        
    }else{
        s=(List)malloc(sizeof(struct LNode));
        s->Data=X;
        s->Next=p->Next;
        p->Next=s;
        return PtrL;//头结点不变 
    } 
}
4.删除(删除链表的第i个位置上的节点)

思考:删除第i个节点需要找到第i-1个节点,然后接到第i+1个节点上去

(1)先找到链表的第i-1个节点,用p指向

(2)用s指针指向i节点

(3)p->next=s->next

(4) 释放i节点


List Delete(int i,List PtrL)
{
    List p,s;
    if(i==1)
    {
        s=PtrL;//s指向要删除的节点 
        if(PtrL!=NULL)
        {
            PtrL=PtrL->Next;
        }else return NULL;
        
        free(s);//释放要删除的节点 
        return PtrL;//返回新头指针 
    }
    
    p=FindKth(i-1,PtrL);//只要删除的节点不是头结点就要找到它的前一个    
    
    if(p==NULL)
    {
        printf("第%d个节点不存在",i-1);
        return NULL; 
    }else if(p->Next==NUll){//即要删除的节点不存在 
        printf("第%d个节点不存在",i);
        return NULL; 
    } else{
        s=p->Next;
        p->Next=s->Next;
        free(s);
        return PtrL;//头指针不变 
    } 
} 

2.1.6广义表与多重链表

例子:二元多项式的表示

分析

广义表定义

广义表(Generalized List):广义表是线性表的推广


广义表中出现的问题:一个域可能是不能分解的单元,也可能是一个指针。

处理:C语言提供了一种手段,联合Union


操作:

typedef struct GNode* GList;
struct GNode{
    int Tag;//标志域:0表示是单元素,1表示节点是广义表
    
    union{
        ElementType Data;
        GList SubList;
    }URegion;
    
    Glist Next;//指向后继节点 
}; 

理解如图:

多重链表:链表中的节点可能同时隶属多个链

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值