线性表总结


在这里插入图片描述

一、线性表的定义


线性表是具有相同数据类型的n个数据元素的有限序列
其中第一个元素称为表头元素,最后一个元素称为表尾元素
除表头元素外,每个元素都有自己的直接前驱
除表尾元素外,每个元素都有自己的直接后继


二、线性表的特点


  1. 元素个数有限
  2. 逻辑上具有顺序
  3. 元素都是数据元素
  4. 每个元素数据类型相同,意味着占有相同大小的存储空间
  5. 具有抽象性

三、线性表的顺序表示(顺序表)

线性表的顺序存储又称顺序表(用一组连续的存储单元依次存储线性表中的元素)。
它的特点是逻辑上相邻的两个元素在物理位置上也相邻。


3.1顺序表存储类型

typedef struct seqList{
    ElemType data[MaxSize]; //顺序表元素
    int length; //顺序表当前长度
}seqList;

3.2顺序表的插入操作 O(n)

bool LinkInsert(seqList *L,int i,ElemType e)
{
    if(i < 1 || i > L-> length + 1) //插入的位置不能小于1或者大于当前长度下下个位置
        return false;
    if(L->length >= MaxSize)  // 表示存储空间已满
        return false;
    for(int j = L->length;j >= i; j--)
    {
        L->data[j] = L->data[j-1]; //依次赋值
    }
    L->data[i-1] = e; //插入位置赋值
    L->length ++;//长度+1
    return true;
}

在这里插入图片描述
时间复杂度为O(n)


3.2顺序表的删除操作 O(n)


bool ListDelete(seqList *list,int i)
{
    //判断元素出界
    if( i < 1 || i > list->length)
        return  false;


    for(int j = i;j<=list->length-1;j++)
    {
        list->data[j-1] = list->data[j];
    }

    list->length--;
    return true;

}

在这里插入图片描述
时间复杂度为O(n)


3.2顺序表的按值查找 O(n)

int LocateElem(seqList *L,ElemType e)
{

    int i;
    for(i = 0; i<L->length;i++)
    {
        if(L->data[i] == e)
            return i+1;
    }
    return 0;

}


3.3顺序表总结

顺序表采用**随机存取**的方式,查找某一个位置的值的时间复杂度为O(1),但删除和插入需要移动大量的元素,其时间复杂度均为O(N)

四、线性表的链式表示

4.1单链表定义

通过一组任意的存储单元来存放线性表中的数据元素,每个链表节点除了自身信息外,还需存放一个指向后继的指针。

typedef struct LNode
{
    ElemType data; //数据
    struct LNode *next; //指针
}LNode,*LinkList;

4.1.1头插法建立单链表(有头结点)

/*头插法建立链表
 * 1.设置头结点指向NULL
 * 2.输入数据域
 * 3.将插入节点的后继节点指向头结点的后继节点 s->next = L->next
 * 4.将头结点的后继节点指向 插入节点        L->next = s
 * */
LinkList List_HeadInsert(LinkList L)
{
    LNode *s ;
    int x; // 数据域
    L = (LinkList) malloc(sizeof(LNode));
    L->next = NULL;
    scanf("%d",&x);
    while(x != 9999)
    {
        s = (LNode *)malloc(sizeof(LNode));
        s->data = x ;
        s->next = L->next;
        L->next = s;
        scanf("%d",&x);
    }
    return  L;
}

在这里插入图片描述

4.1.2头插法建立单链表(无头结点)


LinkList List_HeadInsertWithoutHeadNode(LinkList L)
{
    LNode *s; //工作指针
    int x; //数值
    L = (LinkList) malloc(sizeof(LNode));
    L->next = NULL;
    scanf("%d",&x);
    L->data = x;
    while(x!=9999)
    {   scanf("%d",&x);
        if(x == 9999)
            break;
        s = (LNode *)malloc(sizeof(LNode));
        s->data = x;
        s->next = L;
        L = s;
    }
}

在这里插入图片描述

4.2.1尾插法建立单链表(有头结点)

/*
 * 尾插法建立链表
 * 1.建立头结点
 * 2.建立插入节点 以及 <尾指针节点指向 L >
 * 3.输入数据域
 * 4.将尾指针 的 后继节点指向 插入节点
 * 5.将尾指针指向插入节点
 * 6.将尾指针后继节点指向NULL
 */
LinkList List_TailInsert(LinkList L)
{
    int x;
    L = (LinkList)malloc(sizeof(LNode));
    scanf("%d",&x);

    LNode *s; LNode *r = L;
    while(x != 99990)
    {
        s = (LNode *)malloc(sizeof(LNode));
        s->data = x ;
        r->next = s;
        r = s ;
        scanf("%d",&x);
    }
    r->next = NULL;
    return L;
}

在这里插入图片描述

4.2.1尾插法建立单链表(无头结点)


LinkList List_TailInsertWithoutHeadNode(LinkList L) {
    L = (LinkList) malloc(sizeof(LNode));
    int x;
    LNode *s;
    scanf("%d", &x);
    L->data = x;
    LNode *q ;
    q = L;
    while (x != 9999) {
        scanf("%d",&x);
        if (x == 9999)
            break;
        s = (LNode *) malloc(sizeof(LNode));
        s->data = x;
        q->next = s;
        q = s;
    }
    q->next = NULL;
    return L;
}

4.3按序号查找结点值 O(n)

/*
 * 按序号查找节点值
 * 1.判断查找的位序是否非法
 * 2.建立工作指针 以及位序变量
 * 3.进入循环当 工作指针的next非空 并且 位序变量小于所要查找位序的值
 */

LNode *GetElem(LinkList L,int i)
{
    if(i == 0 )
        return  L;
    if(i < 1)
    {
        return NULL;
    }
    int j = 1; //当前序号
    LNode *s = L ->next;
    while(s != NULL && j < i)
    {
        s = s->next;
        j ++ ;
    }
    return  s ;
}

4.2按值查找表结点 O(n)

/*
 * 按值查找 表节点
 *
 */
LNode *LocateElem(LinkList L,ElemType e)
{
    LNode *s = L->next;
    while(s != NULL && s->data != e)
    {
        s = s->next;
    }
    return  s ;
}

4.3 插入结点操作

/*
 * 在位序x的地方插入节点
 * 1.判断插入位置是否非法
 *
 */
void InsertNode(LinkList L,int x,ElemType e)
{
    if( x < 1 || x >Length(L) + 1)
    {
        return;
    }
    LNode *s = GetElem(L,x-1);
    LNode *q = (LNode *)malloc(sizeof(LNode));
    q->data = e;
    q ->next = s->next;
    s->next = q;
}

在这里插入图片描述

4.4 删除结点操作

void DeleteNode(LinkList L,int x)
{
    if(x < 1 || x > Length(L))
        return;
    LNode *s = GetElem(L,x-1);
    LNode *p =s->next;
    s->next = p->next;
    free(p);
}

在这里插入图片描述

4.5 求表长(时间复杂度O(n))

int Length(LinkList  L)
{
    int len = 0;
    LNode *p = L->next;
    while (p != NULL)
    {
        p = p ->next;
        len ++;
    }
    return  len;
}

五、双链表

5.1双链表定义

typedef struct DNode{
	ElemType data;
	struct DNode * prior,*next;
}DNode,*DLinklist;

5.2插入操作(图示)

在这里插入图片描述

5.3删除操作(图示)

在这里插入图片描述

六、循环链表

6.1循环单链表(图示)

与单链表区别在于最后一个指针指向的是头结点
在这里插入图片描述

6.2循环双链表(图示)

在这里插入图片描述
当没有元素时L的首指针和尾指针都指向自己
在这里插入图片描述

六、静态链表(预先分配一块连续的内存空间)

借助数组描述链式存储结构,以next == -1作为结束标志

typedef struct {
	ElemType data;
	int next;
}SLinkList[MaxSize]


在这里插入图片描述

七 总结

  1. 顺序表既可以随机存取,也可以顺序存取,区分于链表的顺序存取。(注:线性表的顺序存储结构是一种随机存储的存储结构
  2. 顺序存储逻辑上相邻的物理上也相邻,而链式存储逻辑上相邻的物理上未必相邻
  3. 按序查找时间复杂度顺序表优于链表(O(1) and O(n)
  4. 插入删除操作时,顺序表需要移动大量元素,而链表只需要修改相应的指针即可

八 错题


8.1单链表操作的时间复杂度

在一个长度为n的带头结点的单链表h上,设有尾指针r,则执行(B)操作与链表的表长有关。
A删除单链表第一个元素O(1)
B删除单链表中的最后一个元素O(n)
C在单链表第一个元素前插入一个新元素O(1)
D在单链表最后一个元素后插入一个新元素O(1)
B虽然有尾指针但是删除之后还要寻找倒数一个元素使他的指针指向NULL


8.2静态链表的指针问题

静态链表中指针表示的是(C)
A.下一个元素的地址
B.内存储器地址
C下一个元素在数组中的位置
D左链或右链指向的元素的地址
(指针又称游标,指向的是结点的相对地址(数组下标)


8.3各种链表操作的时间复杂度

设对n(n>1)个元素的线性表的运算只有4种:删除第一个元素;删除最后一个元素;在第一个元素之前插入新元素;在最后一个元素之后插入新元素,则最好使用(C)
A.只有尾结点指针没有头结点指针的循环单链表
B.只有尾结点指针没有头结点指针的非循环双链表
C.只有头结点指针没有尾结点指针的循环双链表
D.既有头结点指针又有尾结点指针的循环单链表

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值