线性表

线性表

什么是线性表

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

  • 表中元素个数称为线性表的长度
  • 线性表没有元素时,称为空表
  • 表起始位置称表头,表结束位置称表尾

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

类型名称:线性表

数据对象集:线性表是\(n(\ge0)\)个元素构成的有序序列\((a_1,a_2,\cdots,a_n)\)

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

  1. List MakeEmpty():初始化一个空线性表\(L\)
  2. ElementType 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 i):返回线性表\(L\)的长度\(n\)

线性表的顺序存储实现

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

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\)

主要操作的实现

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

List MakeEmpty(){
    List PtrL;
    PtrL=(List)malloc(sizeof(struct LNode));//通过malloc申请这样一个结构
    PtrL->Last=-1;//把结构的Last设为-1,Last=0表示有一个元素放在第一个位置,空表Last设为-1
    return PtrL;//最后返回这个结构的指针
}

查找

int Find(ElementType X, List PtrL){
    int i=0;
    while(i <= PrtL->Last && PrtL->Data[i] != X)
        i++;//查找成功的平均比较次数为(n+1)/2,平均时间性能为O(n)
    if (i > Ptrl->Last) 
        return -1;//如果没找到,返回-1
    else
        return i; //找到后返回的是存储位置
}

插入

在第\(i\)\(1\le i\le n+1\))个位置上插入一个值为\(X\)的新元素

1就插在线性表的头上;\(n+1\)是插在线性表的最后

线性表是在数组里表示的,下标是从0开始的

实际上要把元素放到i-1的位置

首先,要把i-1之后的这些元素全部往后挪一位,先移动,再插入

从后面开始挪,把第n个元素挪到第n+1个元素上

void Insert(ElementType X, int i, List PrtL){
    int j;
    if (PtrL->Last == MAXSIZE-1){//表空间已满,不能插入
        printf(" 表满 ");
        return;
    }
    if (i < 1 || i>PtrL->Last+1){// 检查插入位置的合法性
        printf(" 位置不合法 ");
        return;
    }
    for (j = PtrL->Last; j >= i-1; j--)
        PrtL->Data[j+1] = PtrL->Data[j]; //将ai~an倒序向后移动
    PtrL->Data[i-1]=X; //新元素插入
    PtrL->Last++; //Last仍指向最后元素
    return;
}

删除

删除表的第\(i\)\(1\le i\le n\)$)个位置上的元素

数组对应的下标就是0到n-1

将第\(i\)个元素移掉,第\(i\)个元素的位置空出来了,所以必须把\(i\)之后的这些元素全部往前挪

要删掉的是第\(i\)个位置上的元素,也就是下标为\(i-1\)的元素

所以这个时候要把它后面的那个元素挪到前面来

下标为\(i\)的元素挪到\(i-1\),下标为\(i+1\)的元素挪到\(i\)

按照从左往右的顺序往前挪

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];//将a_{i+1}~a_n向前移动
    PtrL->Last--; //Last仍指向最后元素
    return;
}
//平均挪动次数为(0+n-1)/2,平均时间性能为O(n)

线性表的链式存储实现

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

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

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

主要操作的实现

求表长

int Length(List PtrL){
    List p = PtrL; //p指向表的第一个结点
    int j=0;
    while (p){
        p=p->Next;
        j++;//当前p指向的是第j个结点
    }
    return j;
}
//时间性能为O(n)

查找

  1. 按序号查找:FindKth
List FindKth(int K, List PtrL){
    List p = PtrL;
    int i = 1;
    while (p != NULL && i < K){ //一个表不空,一个i小于K
        p=p->Next;
        i++;
    }
    if (i == K) 
        return p; //找到第L个返回指针
    else 
        return NULL; //否则返回空
}//平均时间性能为O(n)
  1. 按值查找:Find
List Find(ElementType X, List PtrL){
    List p = PtrL;
    while (p != NULL && p->Data != X) //一个表不空,一个没找到X
        p=p->Next;
    return p; // 一个可能是找到了,返回X所在节点的地址;一个可能是没找到,返回NULL
}//平均时间性能为O(n)

插入

在第\(i-1\,(1\le i\le n+1)\)个结点侯插入一个值为\(X\)的新节点

(1)先构造一个新节点,用\(s\)指向;(用malloc函数来申请一块空间)

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

(3)然后修改指针,插入结点(\(p\)之后插入新节点是\(s\)

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){ //第i-1个不存在,不能插入
        printf(" 参数i错");
        return NULL;
    }
    else{
        s = (List)malloc(sizeof(struct LNode));//申请、装填结点
        s->Data = X;
        s->Next = p->Next;//新节点插入在第i-1个结点的后面
        p->Next = s;
        return PtrL;
    }
}

删除

删除链表第\(i\,(1\le i\le n)\)个位置上的结点

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

(2)再用指针\(s\)指向要被删除的结点(\(p\)的下一个结点);

(3)然后修改指针,删除\(s\)所指的结点

(4)最后释放\(s\)所指结点的空间

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); //查找第i-1个结点,返回第i-1个结点的指针
    if (p == NULL){ //如果第i-1个结点的指针为空
        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;//从链表中删除第i个结点
        free(s);//释放被删除结点的内存空间
        return PtrL;
    }
}
posted @ 2022-03-02 12:59  里列昂遗失的记事本  阅读(141)  评论(0编辑  收藏  举报