第二章 线性表

本文详细介绍了线性表的顺序存储结构(顺序表)和链式存储结构(单链表),包括基本操作如创建、初始化、销毁、查找、插入和删除等,以及相应的函数实现。
摘要由CSDN通过智能技术生成

2.1 线性表及其逻辑结构

2.1.1 线性表的定义

        线性表是一个具有相同特性的数据元素的有限序列

 2.2.1 线性表的顺序存储—顺序表 

        线性表顺序存储结构:把线性表中的所有元素按照顺序存储方法进行存储。按逻辑顺序依次存储到存储器中一片连续的存储空间中。

        顺序表类型声明:

typedef struct{
    ElemType data[MaxSize];        //存放线性表中的元素
    int length;                    //存放线性表的长度
}SqList;                           //顺序表类型

2.2.2 顺序表基本运算的实现

    1.建立顺序表

        整体创建顺序表,即由数组元素a[0..n-1]创建顺序表L。

void CreateList(SqList * &L,ElemType a[],int n){    //由a中的n哥元素建立顺序表
    int i = 0,k = 0;                                //k表示L中元素的个数初始值为0
    L = (SqList *)malloc(sizeof(SqList));           //分配存放线性表的空间
    while (i < n){                                  //i扫描数组a的元素
        L->data[k] = a[i];
        k++; i++;                                   //k 记录插入到 L 中的元素个数
    }
    L->length = k;                                  //设置L的长度k
}

    2.顺序表基本运算算法

        1)初始化线性表:InitList(&L)

        构造一个空的线性表 L 。实际上只需将 length 成员设置为 0 即可。

void InitList(SqList * &L){
    L = (SqList *)malloc(sizeof(SqList));        //分配存放线性表的空间
    L->length = 0;                               //置空线性表的长度为0
}
        2)销毁线性表:DestoryList(&L)

        释放线性表 L 占用的内存空间。

void DestoryList(SqList * &L){
    free(L);                        //释放L所指的顺序表空间
}        
        3)判断线性表是否为空表:ListEmpty(L)

        返回一个值表示 L 是否为空表。若 L 为空表,则返回 true ,否则返回 false 。

bool ListEmpty(SqList *L){
    return(L->length==0);
}
        4)求线性表的长度:ListLength(L)

        返回顺序表 L 的长度。实际上只需返回 length 成员的值即可。

int ListLength(SqList *L){
    return(L->length);
}
        5)输出线性表:DispList(L)

        该运算当线性表 L 不为空时,顺序显示 L 中各元素的值。

void DispList(SqList *L){
    for (int i = 0; i < L->length; i++)
        printf("%d ",L->data[i]);
    printf("\n");
} 
        6)按序号求线性表中的元素:GetElem(L ,i ,&e)
bool GetElem(SqList *L,int i,ElemType &e){
    if (i < 1 || i > L->length)
        return false;                            //参数i错误时返回false
    e = L->data[i-1];                            //取元素的值
    return true;                                 //成功找到元素时返回true
} 
        7)按元素值查找:LocateElem(L ,e)
int LocateElem(SqList *L,ElemType e){
    int i = 0;
    while(i < L->length && L->data[i] != e) 
        i++;                                        //查找元素e
    if (i >= L->length)                            
        return 0;                                   //未找到时返回0
    else
        return i+1;                                 //找到返回其逻辑序号
}
        8)插入数据元素:ListInsert(&L ,i ,e)
bool ListInsert(SqList *&L,int i,ElemType e){
    int j;
    if (i < 1 || i > L->length + 1 || L->length == MaxSize)
        return false;                                       // 参数错误时返回 false
    i--;                                                    // 将顺序表逻辑序号转化为物理序号
    for (j = L->length; j > i; j--)                         // 将data[i..n]元素后移一个位置
        L->data[j] = L->data[j-1];              
    L->data[i] = e;                                         // 插入元素 e
    L->length++;                                            // 顺序表长度增 1
    return true;                                            // 成功插入返回 true
}
        9)删除数据元素:ListDelete(L,i,e)
bool ListDelete(SqList *&L , int i , ElemType &e){
    int j;
    if (i < 1 || i > L->length)                         // 参数错误时返回 false
        return false;
    i--;                                                 // 将顺序表逻辑序号转化为物理序号
    e = L->data[i];
    for (j = i; j < L->length - 1; j++)                  // 将 data[i..n-1] 元素前移
        L->data[j] = L->data[j+1];
    L->length--;                                         // 顺序表长度减 1
    return true;                                         // 成功删除返回 true
}

2.3 线性表的链式存储结构

 2.3.1 线性表的链式存储结构——链表

  2.3.2 单链表

        单链表中结点类型 LinkNode 的声明如下 :       

typedef struct LNode{            
    ElemType data;                // 存放元素值
    struct LNode *next;           // 指向后继结点
}LinkNode;                        // 单链表结点类型

1.插入和删除结点的操作

        1)插入结点的操作

2.建立单链表

        1)头插法建立单链表

        从一个空表开始依次读取字符数组 a 中的元素,生成一个新结点(由s指向它)将读取的数组元素存放到该结点的数据域中,然后将其插到当前链表的表头(即头节点之后),直到数组a中的所有元素读完为止。

void CreateListF(LinkNode *&L,ElemType a[],int n){
    LinkNode *s;
    L = (LinkNode *)malloc(sizeof(LinkNode));
    L->next = NULL;                                   // 创建头结点,其next域置为NULL
    for (int i = 0; i < n; i++){                      // 循环建立数据结点s
        s=(LinkNode *)malloc(sizeof(LinkNode));
        s->data = a[i];                               // 创建数据结点 s
        s->next = L->next;                            // 将 s 插在原开始结点之前,头结点之后
        L->next = s;
    }
}

        本算法的时间复杂度为O(n),其中n为单链表中数据结点的个数。

        2)尾插法建立单链表

        从一个空表开始依次读取字符数组 a 中的元素,生成一个新结点s,将读取的数组元素存放到该结点的数据域中,然后将其插到当前链表的表尾上,直到数组a中的所有元素读完为止。为此需要增加一个尾指针r,使其始终指向当前链表的尾结点,每插入一个新结点后让r指向这个新结点,最后还需要将r所指结点(尾结点)的next域置为空。

void CreateListR(LinkNode *&L,ElemType a[],int n){
    LinkNode *s,*r;
    L = (LinkNode *)malloc(sizeof(LinkNode));         // 创建头结点
    r = L;                                            // r始终指向尾结点,开始时指向头结点
    for(int i = 0; i < n; i++){                       // 循环建立数据结点
        s = (LinkNode *)malloc(sizeof(LinkNode));
        s->data = a[i];                               // 创建数据结点 s
        r->next = s;                                  // 将结点s插入结点r之后
        r = s;
    }
    r->next = NULL;                                   // 尾结点 next 域置为 NULL
}

        本算法的时间复杂度为O(n),其中n为单链表中数据结点的个数。

3.线性表的基本运算在单链表中的实现

        1)初始化线性表:InitList(&L)

        建立一个空的单链表,即创建一个头结点并将其next域置为空。

void InitList(LinkNode * &L){ 
	L = (LinkNode *)malloc(sizeof(LinkNode));        // 创建头结点
	L->next = NULL;                                  // 将其next域置为NULL
}
        2)销毁线性表: DestoryList(&L)
void DestoryList(LinkNode * &L){
    LinkNode *pre = L,*p = L->next;       // pre指向结点p的前驱结点
    while(p != NULL){                     // 遍历单链表L
        free(pre);                        // 释放pre结点
        pre = p;                          // pre、p同步后移一个结点
        p = pre->next;                    
    }                                     // 循环结束时p为NULL
    free(pre);                            // 释放指向尾结点的pre
}
        3)判断线性表是否为空表:ListEmty(L)
bool ListEmpty(LinkNode *L){
    return (L->next == NULL);
}
        4)求线性表的长度:ListLength(L)
int ListLength(LinkNode *L){
    LinkNode *p = L;               // p指向头结点
    int n = 0;                     // n置为0,即头节点的序号为0
    while(p->next != NULL){    
        p = p->next;
        n++;    
    }                              // 循环结束,p指向尾结点
    return (n);                    // 其序号n为结点的个数
}
        5)输出线性表:DispList(L)
void DispList(LinkNode *L){
    LinkNode *p = L->next;            // p指向首结点
    while(p != NULL){                 // p不为NULL
        printf("%d",p->data);         // 输出p结点的data域
        p = p->next;                  // p移向下一个结点
    }    
    printf("\n");
}
        6)按序号求线性表中的元素:GetElem(L,i,&e)
bool GetElem(LinkNode *L,int i,ElemType &e){
    int j = 0;
    LinkNode *p = L;                            // p 指向头结点,j置为0(即头结点的序号为0)
    while(j < i && p != NULL){
        p = p->next;
        j++;
    }
    if (p == NULL)                              // 不存在第 i 个数据结点,返回 false
        return false;
    else{                                       // 存在第 i 个数据结点,返回 true
        e = p->data;
        return true;
    }
}
        7)按元素值查找:LocateElem(L,e)
int LocateElem(LinkNode *L,ElemType e){
    int i = 1;
    LinkNode *p = L->next;                     // p 指向开始结点, i 置为 1 
    while (p != NULL && p->data != e){
        p = p->next;                           // 查找 data 值为 e 的结点,其序号为 i
        i++;
    }
    if (p == NULL)                             // 不存在元素值为 e 的结点,返回 0
        return(0);
    else                                       // 存在元素值为 e 的结点,返回其逻辑序号 i
        return(i);
}
        8)插入数据元素:ListInsert(&L,i,e)
bool ListInsert(LinkNode *&L,int i,ElemType e){
    int j = 0;
    LinkNode *p = L,*s;                             //p 指向头结点, j 置为 0
    while (j < i - 1 && p != NULL) {
        p = p->next;
        j++;
    }
    if (p == NULL)                                  // 未找到第 i-1 个结点,返回 false
        return false;
    else {                                           // 找到第i-1个结点p,插入新结点并返回true
        s = (LinkNode *)malloc(sizeof(LinkNode));
        s->data = e;                                // 创建新结点 s ,其 data 域置为 e
        s->next = p->next;                          // 将 s 插入到 p 之后
        p->next = s;
        return true;
    }
}
        9)删除数据元素:ListDelete(&L,i,&e)
bool ListDelete(LinkNode *&L,int i,ElemType &e){
    int j = 0;
    LinkNode *p = L,*q;                             // p 指向头结点, j 置为 0
    while (j < i-1 && p != NULL){                   // 查找第 i-1 个结点
        p = p->next;
        j++;  
    }
    if (p == NULL)                                  // 未找到第 i-1 个结点,返回 false
        return false;
     else {                                         // 找到第 i-1 个结点 p
         q = p->next;                               // q 指向第 i 个结点
         if (q == NULL)                             // 若不存在第 i 个结点,返回 false
            return false;
         e = q->data;
         p->next = q->next;                         // 从单链表中删除 q 结点
         free(q);                                   // 释放 q 结点
         return true;                               // 返回 true 表示成功删除第 i 个结点
    }
}

4.单链表的应用示例

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值