线性表学习笔记

本文介绍了线性表的基本概念,包括线性表的抽象数据类型描述,并通过多项式表示的问题探讨了线性表的顺序存储和链式存储实现。顺序存储使用数组,适合元素位置连续的情况,而链式存储则通过节点链接实现,方便插入和删除操作。文章详细展示了两种存储方式的操作实现,如查找、插入和删除等。
摘要由CSDN通过智能技术生成

1.线性表

1.1基本概念

多项式的表示

【例】一元多项式及其运算

一元多项式: f ( x ) = a 0 + a 1 x + . . . + a n − 1 x n − 1 + a n x n f(x)=a_0+a_1x+...+a_{n-1}x^{n-1}+a_nx^n f(x)=a0+a1x+...+an1xn1+anxn

主要运算: 多项式相加、相减、相乘等

【分析】如何表示多项式?

多项式的关键数据:

  • 多项式项数 n n n
  • 各项系数 a i a_i ai 及指数 i i i

方式一: 顺序存储结构直接表示

数组各分量对应多项式各项: a [ i ] a[i] a[i]:项 x i x^i xi 的系数 a i a_i ai

例如: f ( x ) = 4 x 5 − 3 x 2 + 1 f(x)=4x^5-3x^2+1 f(x)=4x53x2+1

表示成:

下标i012345
a [ i ] a[i] a[i]10-3004
1 − 3 x 2 -3x^2 3x2 4 x 5 4x^5 4x5

两个多项式的相加: 两个数组对应分量相加

问题: 如何表示多项式 x + 3 x 2000 x+3x^{2000} x+3x2000 ?

该方法容易造成空间的浪费


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

每个非零项 a i x i a_ix^i aixi 涉及两个信息:系数 a i a_i ai 和指数 i i i

可以将一个多项式看成是一个 ( a i , i ) (a_i,i) (ai,i) 二元组的集合。

用结构数组表示: 数组分量是由系数 a i a^i ai 、指数 i i i 组成结构,对应一个非零项

例如: P 1 ( x ) = 9 x 12 + 15 x 8 + 3 x 2 P_1(x)=9x^{12}+15x^8+3x^2 P1(x)=9x12+15x8+3x2 P 2 ( x ) = 26 x 1 9 − 4 x 8 − 13 x 6 + 82 P_2(x)=26x^19-4x^8-13x^6+82 P2(x)=26x194x813x6+82

可以分别表示为:

下标 i i i012
系数 a i a^i ai9153-
指数 i i i1282-
下标 i i i0123
系数 a i a^i ai26-4-1382-
指数 i i i19860-

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

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

下标 i i i012345
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)

P 3 ( x ) = 26 x 1 9 + 9 x 12 + 11 x 8 − 13 x 6 + 3 x 2 + 82 P_3(x)=26x^19+9x^{12}+11x^8-13x^6+3x^2+82 P3(x)=26x19+9x12+11x813x6+3x2+82


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

链表中每个节点 储存多项式中的一个非零项 ,包括系数和指数 两个数据域以及一个指针域

coef (coefficients)expon (exponent)link
typedef struct PolyNode *Polynomial;
typedef struct PolyNode{
    int coef;
    int expon;
    Polynomial link;
}

P1 → \rightarrow 9 | 12 | → \rightarrow 15 | 8 | → \rightarrow 9 | 12 | NULL

P2 → \rightarrow 26 | 19 | → \rightarrow -4 | 8 | → \rightarrow -13 | 6 | → \rightarrow 80 | 0 | NULL

加法运算同上述方法

1.1.1什么是线性表

多项式表示问题的启示:

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

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

  • 表中元素个数称为线性表的长度
  • 线性表没有元素时,称为空表
  • 表起始位置称表头 ,表结束位置称表尾
1.1.2线性表的抽象数据类型描述

类型名称: 线性表(List)

数据对象集: 线性表时n( ≥ \geq 0)个元素构成的有序序列( a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an

操作集: 线性表L ∈ \in List,整数i表示位置,元素X ∈ \in ElementType,线性表基本操作主要有:

  1. List MakeEmpty():初始化一个空线性表L;
  2. ElemeneType FindKth(int K, List L) :根据位序K,返回相应元素;
  3. int Find(ElementType X, List L):在线性表L中查找X的第一次出现位置;
  4. void Insert(ElementType X, int i, List L) :在位序i前插入一个新元素X;
  5. void Delete(int i, List L) :删除指定位序i的元素;
  6. int Length(List L) :返回线性表L的长度n。

1.2线性表的顺序存储实现

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

下标 i i i 0 0 0 1 1 1 i − 1 i-1 i1 i i i n − 1 n-1 n1MAXSIZE-1
Data a 1 a_1 a1 a 2 a_2 a2 a i a_i ai a i + 1 a_{i+1} ai+1 a n a_n an-
typedef struct{
    ElementType Data[MAXSIZE];
    int Last;
}List;
List L, *PtrL;

访问下标为 i i i 的元素: L.Data[i]PtrL->Data[i]

主要操作的实现

  1. 初始化(建立空的顺序表)

    List *MakeEmpty()
    {
        List *PtrL;
        PtrL = (List *)malloc(sizeof(List) );
        PtrL->Last = -1;
        return PtrL;
    }
    
  2. 查找

    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;  //找到后返回的是储存位置
    }```
    
  3. 插入(第 i ( 1 ≤ i ≤ n + 1 ) i(1 \leq i \leq n+1 ) i(1in+1) 个位置上插入一个值为X的新元素)

    先移动,再插入

    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]; //向后移动
        PtrL->Data[i-1] = X; //新元素插入
        PtrL->Last++; //Last仍指向最后yun
        return;
    }
    
  4. 删除(删除表的第 i ( 1 ≤ i ≤ n + 1 ) i(1 \leq i \leq n+1 ) i(1in+1)个位置上的元素)

    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]; // 向前移动
        PtrL->Last--; //Last仍指向最后元素
        return;
    }
    

1.3线性表的链式存储实现(无头节点)

不要求逻辑上相邻的两个元素物理上也相邻;通过“链”建立起数据元素之间的逻辑关系;

插入、删除不需要移动数据元素,只需要修改“链”。

在这里插入图片描述

typedef struct Node
{
    ElementType Data;
    struct Node *Next;
}List;
List L, *PtrL;

主要操作

  1. 求表长

    int Length(List *PtrL)
    {
        List *p = PtrL; //p指向表的第一个节点
        int j = 0;
        while(p)
        {
            p = p->Next; 
            j++;  //当前p指向的是第j个节点
        }
        return j;
    }
    
  2. 查找

    1. 按序号查找: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; //否则返回空
      }
      
    2. 按值查找:Find

      List *Find(ElementType X, List *PtrL)
      {
          List *p = PtrL;
          while(p != NULL && p->Data != X)
              p = p->Next;
          return p;
      }
      
  3. 插入(第 i − 1 ( 1 ≤ i ≤ n + 1 ) i-1(1 \leq i \leq n+1 ) i1(1in+1) 个节点后插入一个值为X的新元素)

    1. 先构造一个新节点,用 s s s 指向;
    2. 再找到链表的第 i − 1 i-1 i1 个节点,用 p p p 指向;
    3. 然后修改指针,插入节点( p p p 之后插入的新节点是 s s s

在这里插入图片描述

List *Insert(ElementType X, int i, List *PtrL)
{
    List *p, *s;
    if(i == 1) //新节点插入在表头
    {
        s = (List *)malloc(sizeof(List)); //申请、填装节点
        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(List)); //申请、填装节点
        s->Data = X;
        s->Next = p->Next; //新节点插入在第i-1个节点的后面
        p->Next = s;
        return PtrL;
    }
}
  1. 删除(删除链表的第 i ( 1 ≤ i ≤ n ) i(1 \leq i \leq n ) i(1in)个位置上的节点)

    1. 先找到链表的第 i − 1 i-1 i1 个节点,用 p p p 所指节点;
    2. 再用指针 s s s 所指向要被删除的节点( p p p 的下一个节点);
    3. 然后修改指针,删除 s s s 所指节点;
    4. 最后释放 s s s 所指节点的空间;
    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;
        }
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值