数据结构学习笔记(第二章线性表)

目录

第二章 线性表

1.定义:

2.线性表的基本操作

3.顺序表

顺序表的基本操作

4.链表

单链表:

单链表基本操作

 双链表

 循环链表

 静态链表

第二章 线性表

1.定义:

线性表是具有相同数据类型的n(n>=0)个数据元素的有限序列,其中n为表长,当n=0时线性表是一个空表。若用L命名线性表,则其一般表示为

L=(a1,a2,.....an)

a1是表头元素,an是表尾元素。除a1外都有前驱,除an外都有后继

线性表是一种逻辑结构,表示元素之间一对一的相邻关系。

线性表包括顺序表和链表,顺序表里面元素的地址是连续的。链表里面节点的地址不一定连续的,是通过指针连起来的。顺序表和链表是指存储结构。

2.线性表的基本操作

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

Length(L):求表长

LocateElem(L,e):按值查找操作

GetElem(L,i):按位查找操作

ListInsert(&L,i,e):插入操作

ListDelete(&L,i,&e):删除操作

PrintList(L):输出操作

Empty(L): 判空操作

DestroyList(&L):销毁操作

注意:&表示c语言中的引用调用,在c语言中用指针也可达到同样效果。

请参考

c语言 引用调用_C中按值调用和按引用调用之间的区别_culing2941的博客-CSDN博客

3.顺序表

线性表的顺序存储又称顺序表,逻辑地址上相邻的地址元素,物理地址也相邻。

特点:表中元素逻辑顺序与物理顺序相同,用数组实现的,一维数组可以是静态的,也可以是动态的。

静态分配
#define MaxSize 50//定义线性表最大长度
typedef struct{
    ElemType data[MaxSize];//顺序表元素
    int length;//顺序表当前长度
}SqList//顺序表类型定义


动态分配
#define InitSize 100//初始化表长度
typedef struct{
    ElemType *data;//指示动态分配数组的指针
    int MaxSize,length;//数组最大容量和当前个数
}SeqList//类型定义

动态分配初始化语句:
c:     L.data=(ElemType*)malloc(sizeof(ElemType)*InitSize);
c++:   L.data=new ElemType[InitSize];
注:动态分配不是链式存储,他是顺序存储结构,物理结构并没有发生变化,依然是随机存取方式,只是分配的空间大小可以在运行时动态决定。

注:线性表从1开始,而数组从0开始。

优点:随机访问特性,查找O(1)时间,存储密度高;逻辑上相邻的元素,物理上也相邻;

缺点:插入删除需移动大量元素。

顺序表的基本操作

插入操作:

最好情况:表尾插入,时间复杂度o(1)

最坏情况:表头插入,时间复杂度o(n)

平均情况:o(n/2)=o(n)

删除操作: 

最好情况:表尾删除,时间复杂度o(1)

最坏情况:表头删除,时间复杂度o(n)

平均情况:o(n/2)=o(n)

查找操作:

int LocateElem(SqList L,ElemType e){
    int i;
    for(i=0;i<L.length;i++{
        if(L.data[i]==e)
            return i+i;//返回其位序
    return 0;//查找失败
}

最好情况:表头查找,时间复杂度o(1)

最坏情况:表尾查找或查找失败,时间复杂度o(n)

平均情况:o(n/2)=o(n)

4.链表

与顺序存储相比,允许存储空间不连续,插入删除时不需要移动大量的元素,只需修改指针即可,但查找某个元素,只能从头遍历整个链表。且不能随机存取

单链表:

定义:

 单链表分为带头结点和不带头结点两种,不管有没有头结点,头指针都指向链表的第一个节点(头结点是第一个结点)。

头结点:数值域可不设任何信息,头结点的指针域指向链表的第一个元素。

带头节点的好处有:

(1)链表第一位置节点上的操作和其它位置上的操作一致

(2)无论链表是否为空,头指针都指向头结点(非空),空表和非空表处理一样

单链表基本操作

1.头插法建立新链表

 

 读入数据顺序与生成链表元素顺序是相反的。每个节点插入时间为o(1),设单链表长为n,则总时间复杂度为o(n)

如果没有设立头结点,则需要在每次插入新节点后,将他的地址赋值给头指针L。

2.尾插法

 

LinkList List_TailInsert(LinkList &L){
    int x;
    L=(LinkList)malloc(sizeof(LNode));
    LNode *s,*r=L;//r为尾指针
    scanf("%d",&x);//输入结点值
    while(x!=9999){//9999表示结束
        s=(LNode *)malloc(sizeof(LNode));
        s->data=x;
        r->next=s;
        r=s;//r指向新的表尾指针
        scanf("%d",&x);
    }
    r->next=NULL;//尾指针指置空
    return L;
}
时间复杂度与头插法相同

3.按序号查找结点值

 时间复杂度o(n)

4.按值查找表结点

时间复杂度o(n)

5.插入结点操作

 本算法主要时间开销在查找i-1元素上,时间复杂度为o(n),若结点已给定,则在其后插入结点时间复杂度为o(1)。

 6.删除结点操作

 时间复杂度为o(n)

 7.求表长操作

 双链表

由于单链表插入删除都得从头遍历,比较麻烦,时间复杂度高。所以我们引入了双链表来解决

主要就是结点中有两个指针,分别指向前驱和后继

typedef struct DNode{
    ElemType data;//数据域
    struct DNode *prior,*next;//前驱后继指针
}DNode, *DLinkList;

 由于引入了双指针,所有我们的插入删除时间复杂度变为了o(1)

1.插入

 2.删除

 循环链表

 1.循环单链表

引用这种后,我们对表头表尾操作的时间复杂度都变为了o(1)

2.循环双链表

 

 静态链表

借助数组来描述线性表的链式存储结构,结点也有数据域和指针域。

左边为静态链表示例,右图为静态链表对应的单链表

#define MaxSize 50//定义静态链表的最大长度
typedef struct{
    ElemType data;//存储数据类型
    int next;//下一个元素的数组下标
}SLinkList[MaxSize];

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

低调$(生活)

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

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

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

打赏作者

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

抵扣说明:

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

余额充值