数据结构学习之线性表笔记总结

概念

线性表(linear list) 是 数据结构 的一种,一个线性表是n个具有相同特性的数据元素的 有限序列 。 线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的(注意,这句话只适用大部分线性表,而不是全部。(来自百度)

基本含义解析及特点

  • 除第一个元素外,每一个元素都有一个直接前驱元素,除最后一个元素外,每一个元素都有一个直接后驱元素,如图:
    https://img-home.csdnimg.cn/images/20220524100510.png
  • 数据元素是组成数据的基本单位,是数据集合的个体,在计算机中通常作为整体进行处理,也称结点记录数据项是有独立含义的数据最小单位,也称项或字段
  • 数据对象是性质相同的数据元素的集合,是数据的一个子集
  • 线性表由有限个元素组成,且由同类型数据元素组成,每一个数据元素都属于同一个数据对象

分类(根据底层存储空间)

在这里插入图片描述

具体应用及功能代码
  • 顺序表
    用一段地址连续的存储单元依次存储线性表的数据元素。顺序存储结构在逻辑结构和物理存储结构中都是依次序互相紧挨着。每个数据元素的地址=首元素的地址+一个该数据类型所占空间大小*数组下标。具体如图:
    顺序表的存储方式及地址关系
    优点:内存空间连续,尾插尾删效率较高,支持随机访问(用下标操作访问)
    缺点:插入或删除都伴随元素的移动,效率较低,顺序表长度固定,有时需要扩容

头文件及宏定义

#include <stdio.h>
#include <stdlib.h>
//返回真或返回假
#define TRUE 1
#define FALSE 0
//返回执行状态
#define OK 1
#define ERROR 0
#define INFEASIBLE -1

#define OVERFLOW -2 //内存分配失败,用于exit语句

typedef int Status;   //定义函数返回类型
typedef int ElemType; //定义元素类型

#define LIST_INIT_SIZE 100 //顺序表【初始空间分配量】
#define LISTINCREMENT 10   //顺序表空间分配【增量】

(1)创建顺序表及顺序表结构体定义:

typedef struct
{
   ElemType *elem; //存储表元素的数组指针
   int length;     //表长度【实际】
   int listsize;   //数组尺寸【最大】
} SqList;

(2)顺序表初始化:

Status InitList(SqList *L)
{
    L->elem = (ElemType *)malloc(LIST_INIT_SIZE * sizeof(ElemType)); //为顺序表分配内存空间
    if (!L->elem)                                                    //检测是否内存溢出
        exit(OVERFLOW);
    L->length = 0;                //将表长初始化为0(因为里面还没有元素)
    L->listsize = LIST_INIT_SIZE; //设置顺序表最初的最大空间
    return OK;
}

附:malloc函数用法:link
(3)打印输出整个顺序表

void printList(SqList L)
{
    for (int i = 0; i < L.length; i++) //遍历整个表
        printf("%d ", L.elem[i]);
    printf("\n");
    return;
}

(4)在顺序表中插入

Status ListInsert(SqList *L, int i, ElemType e)
{
    if (i < 1 || i > L->length + 1) //检查i是否合法,小于1则i-1不能作为数组下标,大于length+1则数组越界
        return ERROR;
    if (L->length >= L->listsize) //检查顺序表是否已经最大,若最大,则进行下面操作来为顺序表增加内存,以便于继续进行插入操作
    {
        ElemType *newbase = (ElemType *)realloc(L->elem, (L->listsize + LISTINCREMENT) * sizeof(ElemType)); //新建一个数组指针,为其分配listsize+LISTINCREMENT的内存空间
        if (!newbase)                                                                                       //检查内存是否分配成功
            exit(OVERFLOW);
        L->elem = newbase;            //将表转移到新的内存空间里去
        L->listsize += LISTINCREMENT; //更新空间最大值
    }
    ElemType j;
    for (j = L->length - 1; j >= i - 1; j--) //将所要插入的位置之后的元素全部向后挪一位
        L->elem[j + 1] = L->elem[j];         // 元素后移
    L->elem[i - 1] = e;                      // 插入e
    ++L->length;                             //更新表长
    return OK;
}

(5)在顺序表中删除

Status ListDelete(SqList *L, int i)
{
    if (i < 1 || (i > L->length)) //检查i是否合法
        return ERROR;
    ElemType *p = &(L->elem[i - 1]); //将指针p定位到要删除的位置
    ElemType *q;
    q = L->elem + L->length - 1; //将指针q定位到顺序表的最后一位
    for (++p; p <= q; ++p)       //将要删除的元素的后面元素以此向前挪动(相当于覆盖掉要删除的元素)
        *(p - 1) = *p;
    --L->length; //更新表长
    return OK;
}

(6)在顺序表中查找

Status GetElem(SqList *L, int i, ElemType &e)
{
    ElemType *p;
    p = L->elem + i - 1; //将指针p定位到要查找的元素位置
    e = *p;              //将此元素赋值给e
    return OK;
}

(7)返回顺序表中元素个数

int ListLength(SqList *L)
{
    return L->length;
}
  • 链表

链表是一种物理存储单元上非连续非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。它不像顺序表那样连续存储元素,而是在每一个节点里存到下一个节点的指针(Pointer)。如图:
在这里插入图片描述
优点:内存空间不连续,头插头删效率高,没有空间限制,不会溢出,可以存储很多元素
缺点:不支持随机访问,查找效率低,需遍历查找
头文件及宏定义

#include <stdio.h>
#include <stdlib.h>
//返回真或返回假
#define TRUE 1
#define FALSE 0
//返回执行状态
#define OK 1
#define ERROR 0
#define INFEASIBLE -1

#define OVERFLOW -2 //内存分配失败,用于exit语句

typedef int Status;   //定义函数返回类型
typedef int ElemType; //定义元素类型

#define LIST_INIT_SIZE 100 //顺序表【初始空间分配量】
#define LISTINCREMENT 10   //顺序表空间分配【增量】

(1)创建链表与结点

typedef struct LNode
{
    ElemType data;      //结点的数据
    struct LNode *next; //结点所指向的下一个结点的地址
} LNode, *LinkList;

(2)对链表进行初始化

LinkList initList()
{
    LinkList L;                          //代表整个链表的结构体指针L(也就是表头L)
    L = (LinkList)malloc(sizeof(LNode)); //为L分配内存,大小为一个结点
    L->next = NULL;                      //表头L暂时指向空,因为才初始化这个链表,目前还没有元素存在
    return L;                            //返回表头L
}

(3)在链表头部插入元素

Status insertHead(LinkList L, ElemType e)
{
    LinkList node;                          //新建一个结点指针
    node = (LinkList)malloc(sizeof(LNode)); //为该结点分配内存空间
    node->data = e;                         //将该结点的数据赋值为e
    node->next = L->next;                   //将这个结点指向L的下一个结点【注意:此时,表头L与结点同时指向相同结点】
    L->next = node;                         //将表头指向node结点【注意:此时,表头指向node,node指向下一个结点,就相当于将node结点插到了表头后面,完成了插入操作】
    return OK;
}

(4)查找元素的值

Status getElem(LinkList L, int i, ElemType &e)
{
    LinkList p = L; //定义一个p指针代表整个链表
    while (i > 0)   //通过遍历指针,找到要查找的元素
    {
        p = p->next; //向后遍历
        i--;         //i持续自减直到找到元素所在的位置
    }
    e = p->data; //将所要寻找的元素的值赋值给e
    return OK;
}

(5)删除元素

Status deleteElem(LinkList L, int i, ElemType &e)
{
    LinkList p = L; //定义一个p指针代表整个链表
    while (i > 1)   //通过遍历指针,找到要查找的元素的前一个元素
    {
        p = p->next;
        i--;
    }
    e = p->next->data;       //将所要寻找的元素的值赋值给e
    p->next = p->next->next; //将要删除的元素的前一个元素的指针直接指向要删除的元素的下一个元素,相当于没有指针指向要删除的元素,此时就删除了元素
    return OK;
}

(6)查找链表长度

int listLength(LinkList L)
{
    LinkList p = L; //定义一个p指针代表整个链表
    int count = -1;
    while (p != NULL) //遍历链表直到指针指向为空,说明此时已经遍历到最后一个元素
    {
        p = p->next;
        count++; //每向后挪一位,计数器就加一
    }
    return count; //返回计数器的值
}

(7)摧毁链表

Status destroyList(LinkList L)
{
    LinkList p = L; //定义一个p指针代表整个链表
    LinkList q;
    while (p)
    {
        q = p->next; //让q指向p的下一个结点
        free(p);     //释放p结点
        p = q;       //又让p继续指向下一个结点
    }
    L->next = NULL;
    return OK;
}

(8)打印链表

Status printList(LinkList L)
{
    LinkList p = L->next;
    if (!p)
    {
        printf("Empty list.\n");
        return OK;
    }
    printf("List:");
    while (p)
    {
        printf("%d ", p->data);
        p = p->next;
    }
    printf("\n");
    return OK;
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

微睇藐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值