首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【自考】数据结构中的线性表,期末不挂科指南,第2篇

【自考】数据结构中的线性表,期末不挂科指南,第2篇

作者头像
梦想橡皮擦
发布于 2019-12-12 07:08:34
发布于 2019-12-12 07:08:34
57200
代码可运行
举报
运行总次数:0
代码可运行

线性表

这篇博客写的是线性表相关的内容,包括如下部分,先看下有木有期待

  1. 啥是线性表
  2. 线性表的顺序存储
  3. 线性表的基本运算在顺序表上的实现
  4. 线性表的链式存储
  5. 线性表的基本运算在单链表上的实现
  6. 循环链表与双向循环链表

Over,内容还蛮多的!~  ̄□ ̄||,头大了...

首先明确一个非常重要的点

线性表是一个线性结构,注意上篇博客提过线性结构是数据的逻辑结构中的一种

基本概念

线性表是由n(n≥0)个数据元素组成的有穷序列

大白话:在内存上一个个排着,找到一个,剩下的挨着找就行

数据元素又称作结点

吐槽:人类在创造术语的路上就是这么带劲,上节课刚说数据元素又称元素,这又来一个结点,得,记住吧

结点个数叫做表长,那么我们用一张完整的图来说明一下

线性表的基本运算,需要了解一下

  1. 初始化 Initiate(L)
  2. 求表长 Length(L)
  3. 读表元素 Get(L,i)
  4. 定位 Locate(L,i)
  5. 插入Insert(L,x,i)
  6. 删除Delete(L,i)

线性表的顺序存储

用顺序存储实现的线性表称为顺序表。一般使用数组来表示顺序表

接下就是刺激的时刻了,比较难的部分来了,因为要用C来实现线性表的基本运算

首先假定线性表的数据元素的类型为DataType ,这个DataType 可以是自定义的,也可以是默认的int,char等类型

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const int Maxsize = 100 ;  // 预先定义一个足够大的常数
typedef struct{
    DataType data[Maxsize]; // 存放数据的数组
    int length ; // 顺序表的实际长度
} SeqList; // 顺序表类型名为SeqList  
SeqList L ;  // 定义一个L为顺序表

实现插入操作,函数名字为InsertSeqList(SeqList L,DataType x,int i) 表示在顺序表第i(1≤i≤n+1)个元素之前,插入一个新元素。使得线性表长度加1。

上面是逻辑上的C语言实现,接下来咱们先引用一个图,说明一下如何用C语言在内存上开辟一块空间,并且向里面存数据

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
#include <stdlib.h>

const int Maxsize = 10;
typedef struct SeqList{
    int *data; //一个int指针,后面用来初始化数组用
    int length;
} seq;

// 顺序表的初始化函数
seq init(){
    seq s;
    s.data = (int*)malloc(Maxsize*sizeof(int)); // 构造一个空的顺序表,动态申请存储空间
    if(!s.data) // 如果申请失败,退出程序
    {
        printf("初始化失败");
        exit(0);
    }
    s.length = 0; // 空表的长度初始化为0
    return s;
}

上述代码,相当于在内存上做了图示的操作

开辟空间之后,向每个小格子里面添加数字

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void display(seq s){
    for(int i=0;i<s.length;i++){
        printf("%d",s.data[i]);
    }
    printf("\n");
    
}

int main()
{
    seq s = init();
    //添加一个元素进入
    for(int i=1;i<=5;i++){
        s.data[i-1] = i;
        s.length++;
    }
    printf("初始化之后,表的数据为:\n");
    display(s);

    return 0;
}

可以看动画理解

添加元素完成之后,就是删除元素

删除的基本步骤

  1. 结点a~i+1~,....a~n~依次向左移动一个元素位置
  2. 表长度减1

看一下代码吧

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
seq delete_seq(seq s,int i){
    if(i<1||i>s.length){
        printf("位置错误");
        exit(0);
    }
    
    // 第i个元素下标修改为i-1
    for(int j=i;j<s.length;j++){
        s.data[j-1] = s.data[j];
    }
    
    s.length--;
    return s;
}

接下来实现定位的算法,说白了,就是判断一个值(x)的位置(i)

C语言的代码如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 注意,这个地方需要返回的为int了,也就是位置
int locate(seq s,int x){
    int i =0;
    while((i<s.length)&&(s.data[i]!=x)){
        i++;
    }
    if(i<s.length) return i+1;
    else return -1;
}

线性表的顺序存储的时间复杂度

运算

插入

删除

定位

求表长

读取元素

时间复杂度

O(n)

O(n)

O(n)

O(1)

O(1)

具体是怎么来的,需要你自己看看算法的实现喽,通过上述表格知道 顺序表的插入、删除算法在时间性能方面不是很理想,接下来我们就采用线性表的链接存储来看一下,是否存在优化。

线性表的链接存储

链式存储结构,上来需要记住有三种常见的 单链表循环链表双向循环链表

首先明确,单链表中每个结点由两部分组成

  • data表示==数据域==
  • next表示==指针域==或==链域==

一些简单的结点概念

线性表在单链表上实现基本运算

接下来重头戏来了,我们要用代码实现一个简单的单链表

空的单链表由一个头指针和一个头结点组成

初始化

初始化之前,我们需要先用C语言定义一个新的结构体

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//链表中的每个结点的实现
//包含数据域与指针域
typedef struct node{
    int data;// 数据域,为了计算方便,类型设置为数字
    struct node *next; // 指针域,指向后继元素
} Node,*LinkList;

结构体定义好了之后,就可以开始初始化操作了 头结点初始化其实就是在内存上开辟一块空间,然后将指针域指向NULL

请看代码,注意返回的是一个指针类型,说白了就是头结点的地址

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 初始化
LinkList init(){
    Node *L; // 定义一个头结点
    L =(LinkList)malloc(sizeof(Node)); //头结点申请地址
    if(L == NULL){
        printf("初始化失败!\n");
        exit(0);
    }
    L->next =NULL;
    return L;
}

初始化成功,开始插入元素

插入元素,有头插入、尾插、任意插

先说一下头插,当头结点初始化完毕之后,第一个元素插入进来就比较简单了,看动图

这是插入一个元素,在用头插法插入第二个元素呢?

新生成的pnew2首先将自己的指针域指向头结点的指针域pnew2->next = L.next,然后L.next = pnew2 即可

上述的逻辑写成代码如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 头插入法
void insert_head(Node *L){
    int i,n,num;  // n表示元素的个数 
    Node *pnew;
    printf("请输入要插入的元素个数:n = ");
    scanf("%d",&n);
    for(i=0;i<n;i++){
        printf("请输入第%d个元素: ",i+1);
        scanf("%d",&num);
        pnew = (LinkList)malloc(sizeof(Node));
        pnew->data = num; // 将数字存储到数据域
        pnew->next = L->next; // 指针域指向L(头结点)的指针域
        L->next = pnew; // 头结点指针域指向新结点地址
        
    }
}

接下来看一下尾插法,其实理解起来也不难,说白了就是在链表后面追加元素即可

代码如下,这个地方看一下里面有一个p=L请问直接使用L可以吗?为什么不直接用,搞清楚了,你也就明白了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 尾插法
void insert_tail(Node *L){
    int i,n,num;
    Node *p,*pnew;
    p = L;
    
    printf("要输入元素的个数:n = ");
    scanf("%d",&n);
    for(i=0;i<n;i++){
        
        printf("请输入第%d个元素:",i+1);
        scanf("%d",&num);
        pnew = (LinkList)malloc(sizeof(Node));
        if(pnew == NULL){
            printf("初始化失败");
            exit(0);
        }
        pnew->data = num;
        p->next = pnew;
        p = pnew;
        
    }
    p->next = NULL;
  
}

剩下的算法实现就比较简单了,例如求表长,通过循环的方式,计算一下即可

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//求表长
int get_length(LinkList L){
    LinkList p;
    int length = 0;
    p = L->next;   // p 指向第一个结点
    while(p){
        printf("单链表的数据为%d\n",p->data);
        length++;
        p = p->next;
    }
    return length;
}

读表中的元素

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 读表中的元素
LinkList get_element(LinkList L,int i){
    // 在单链表L中查找第i个结点,若找到,则返回指向该结点的指针,否则返回NULL
    Node *p;
    p = L->next;
    int position = 1;
    while((position<i)&&(p!=NULL)){ // 当未到第i结点且未到尾结点时继续后移
        p = p->next;
        position++;
    }
    if(i==position) return p; //找到第i个结点
    else return NULL;   // 查找失败
}

读取表的元素,还可以按照值去找,返回位置,尝试一下吧,写起来都是比较容易的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int get_element_by_data(LinkList L,int x){
    Node *p;
    p = L->next;
    int i = 0;
    while(p!=NULL && p->data == x){
        p = p->next;
        i++;
    }
    if (p!=NULL) return i+1;
    else return 0;
}

写个复杂点的,在任意位置插入一个元素,这个还是好玩一些的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/在任意位置插入元素,x为要插入的内容,i为插入的位置
void insert(LinkList L,int x,int i){
    
    Node *p,*q; //p表示要插入的元素,q表示要被插入的元素
    if(i==1) q = L; //如果i==1,那么p=L进行初始化操作
    else q = get_element(L,i-1); // 找到第i-1个元素
    
    if(q==NULL){
        printf("找不到位置");
        exit(0);
    }
    else{
         p =(LinkList)malloc(sizeof(Node));
         p->data = x;
         p->next = q->next; // 新生成的p指向q的下一个结点
         q->next = p;//q的指针域指向新生成的p
        
    }
}

简单说明一下吧 大白话为 要在第i个位置插入一个元素x,那么需要找到i-1位置的元素,这个元素叫做 q

让新元素p(数据域为x,指针域为空)的指针域指向第i 元素,也就是q原先的指针域,==防止丢失掉==

然后在叫q的指针域指向p的地址即可,如果还不明白,看图

对于删除任意位置的节点,这个就要留给你自己了

如果将a~i~移除链表,需要找到直接前驱,让直接前驱的指针域指向a~i+1~的地址就可以了

记得,通过free(p)释放结点

删除全部结点也需要自己完成一下,尽量把代码写完哦~~~

单链表的时间复杂度

  • insert(LinkList L,int x,int i) 时间复杂度为O(n^2^)
  • 头插法和尾插法时间复杂度为O(n)

循环链表

环状链表只需要将表中最后一个结点的指针指向头结点,链表就形成了一个环 如图

循环链表如何想研究一下可以去实现约瑟夫环,由于本教材中不是重点,所以选修即可

双向循环链表

双向循环链表就是在单链表中的每个结点在增加一个指向直接前驱的指针域prior ,这样每个结点就有两个指针了

注意点

  1. 双向循环链表是一种对称结构,即可以直接访问前驱结点又可以直接访问后继结点,所以找前驱和后继结点的时间复杂度都是O(1),也可以得到结论双向循环链表适合应用在需要经常查找结点的前驱和后继场合
  2. p = p->prior->next = p->next->prior

教材中重点给出了删除和插入的两个逻辑,我们看一下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// p表示的是待删除的结点
p->prior->next = p->next;
p->next->prior = p->prior;
free(p)

图示如下

大白话 先让p等于要删除的结点,然后把p删除前,需要将p的前驱和后继结点连接起来,刚才的代码干的就是这个事情!

插入逻辑

在p所指的结点后面插入一个新结点*t,需要修改四个指针:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
t->prior = p;
p->next = t;  // 这两个步骤将t和p连接起来了

t->next = p->next;
p->next->prior = t; //这两个步骤将t和p后继结点连接起来了

期末考试

这章是期末考试或者自考的一个比较重要的考试章节,一般会出现算法设计题,难度系数挺高的

建议,在能力范围内用C语言实现顺序表的基本运算,实现单链表的基本运算

懵了吧,嘿嘿~,多看几遍,多看几遍,看图,看图,写代码,运行,运行

欢迎关注,梦想橡皮擦公众号哦~

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-12-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
数据结构之线性表
所谓顺序表就是顺序存储的线性表。顺序存储是用一组地址连续的存储单元依次存放线性表中各个元素的存储结构。
C语言与CPP编程
2020/12/02
9030
数据结构之线性表
【图解数据结构】 线性表
1.线性表的定义 若将线性表记为(a1,...,ai-1,ai,ai+1,...,an),则表中ai-1领先于ai,ai领先于ai+1,称ai-1是ai的直接前驱元素,ai+1是ai的直接后继元素。
撸码那些事
2018/06/21
1.3K5
数据结构学习—线性表
线性表 线性表的概念 定义 线性表是由n(n>=0)个类型相同的数据元素组成的有限序列,数据元素之间是一对一的关系,即每个数据元素最多有一个直接前驱和一个直接后驱。 特点: 同一性:线性表必须由同类数据元素组成 有穷性:线性表由有限个数据元素组成,表长就是表中数据元素个数 有序性:线性表中相邻元素之间存在着序偶关系。 线性表的顺序存储 定义 是指用一组地址连续的存储单元依次线性表中的各个元素,使得线性表在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中。 C语言定义 #define MAXSI
用户5513909
2023/04/25
1840
数据结构学习—线性表
数据结构-线性表
线性表是具有相同数据类型的n(n≥0)个数据元素的有限 序列,其中n为表长,当n = 0时线性表是一个空表。若用L命名线性表,则其一般表示为:
计蒙不吃鱼
2025/06/12
840
数据结构-线性表
【数据结构】线性表代码实现:顺序存储结构 | 链式存储结构
单链表插入:头插法(往前插入)void head_insert(Node*node,int key)
CtrlX
2023/03/21
1.6K0
【数据结构】线性表代码实现:顺序存储结构 | 链式存储结构
期末复习之数据结构 第2章 线性表
#include <iostream> using namespace std; #define ElemType int #define Status int #define MAXSIZE 100 typedef struct LNode { ElemType data;//数据域 struct LNode* next;//指针域 }LNode, * LinkList; Status InitList(LinkList& L) { L = new LNode; L->next = NULL; return 1; } Status InsertList(LinkList& L, int pos, ElemType e) { LNode* s; LinkList p = L; int j = 0; while (p&&(j<pos-1)) { p = p->next; ++j; } if (!p || j > pos - 1) { return 0; } s = new LNode; s->data = e; s->next = p->next; p->next = s; return 1; } int main() { LinkList P; InitList(P); int num; cout << "请输入整数,按ctrl+z结束输入" << endl; int Length = 1; while (cin>>num) { Length++; InsertList(P, Length, num); } cout <<"单链表结点个数为:"<< Length-1 << endl; }
henu_Newxc03
2021/12/28
7410
期末复习之数据结构 第2章 线性表
【数据结构】线性表代码实现:顺序存储结构 | 链式存储结构
单链表插入:头插法(往前插入)void head_insert(Node*node,int key)
CtrlX
2022/11/18
2K0
【数据结构】线性表代码实现:顺序存储结构 | 链式存储结构
数据结构:线性表的基本操作与链式表达
● LocateElem(L,e): 按值查找操作。在表工中查找具有给定关键字值的元素。
钮祜禄.爱因斯晨
2025/05/31
1130
数据结构:线性表的基本操作与链式表达
数据结构(三):线性表
该序列中所含的元素个数叫做线性表的长度,用 n表示(n>=0)。当 n=0时,表示线性表是一个空表,即表中不包含任何数据元素。
渔父歌
2018/09/10
8480
【数据结构】详细剖析线性表
经过这段时间的学习与分享,想必大家跟我一样都已经对线性表的相关内容比较熟悉了。为了更好的巩固线性表相关的知识点,下面我们一起将线性表这个章节的内容梳理一遍吧。
蒙奇D索隆
2024/01/01
3170
【数据结构】详细剖析线性表
数据结构实验之链表
1、线性表: 线性表是最基本的一种数据结构。线性表是数据结构的一种,一个线性表是n个具有相同特性的数据元素的有限序列。
LucianaiB
2025/05/28
970
数据结构实验之链表
数据结构与算法 -线性表链式存储及其相关算法
链表的具体存储用一组任意的存储单元来存放,链表中结点的逻辑次序和物理次序不一定相同,还必须存储指示其后继结点的地址信息。
越陌度阡
2020/11/26
5670
数据结构与算法 -线性表链式存储及其相关算法
java算法刷题00——数据结构基础知识回顾
数据、数据元素(如一个账号)、数据项(密码、昵称)、数据结构(具有关系的一组数据元素集合,联想汉字的结构其实就是具有布局关系的符号组合)、数据对象(具有相同性质的数据元素的集合、一家海底捞的排队信息可以看作数据结构、全国所有门店排队信息看做同一个数据对象,它们虽无直接关系,但是具有同样的联系)
半旧518
2022/10/26
3160
循环链表及线性表的应用
问题描述:编号为1,2,···,n的n个人围坐在一圆桌旁,每人持有一个正整数的密码。从第一个人开始报数,报到一个预先约定的正整数m时,停止报数,报m的人退席,下一个人又重新从1开始报数,依此重复,直至所有的人都退席。编一程序输出他们退席的编号序列。例如,设m=20,n=7,7个人的密码依次是3,1,7,2,4,8,4,则退席的人的编号依次为6,1,7,5,3,2,4。
用户6754675
2020/05/26
5930
《大话数据结构》线性表代码总结
//线性表存储的结构代码 #include<stdio.h> #include<stdlib.h> #include<time.h> #define MAXSIZE 1000//静态链表部分的 #define MAX_SIZE 20//最大长度 #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 //线性表顺序存储结构 //自定义的类型 以描述返回状态值 typedef int Status;//Status是函数的类型,其值是函数结果的状
半生瓜的blog
2023/05/12
2250
《大话数据结构》线性表代码总结
数据结构—线性表
本篇开始,又会开始一个新的系列,数据结构,数据结构在算法或者是编程中的重要性不言而喻,所以学好数据结构还是很有必要的。本篇主要介绍数据结构的第一个结构——线性表,主要分为以下几部分: 1.概念 2.存储结构
张俊红
2018/07/30
7500
数据结构—线性表
【数据结构】线性表----链表详解
前面我们介绍的顺序表,在逻辑结构和物理结构上都是线性、连续的关系,那么我们在篇尾的时候也提到了是否有一种顺序表,无需在物理结构上连续,从而达到更好存取的目的呢?今天它来了。
Skrrapper
2024/06/18
1810
【数据结构】线性表----链表详解
【数据结构】线性表
文章目录 2. 线性表 2.1 概述 2.2 顺序表 2.2.1 定义 2.2.2 地址公式 2.2.3 顺序表特点 2.2.4 算法:插入 2.2.5 算法:删除 2.2.6 算法:查找 2.2.7 顺序表局限性: 2.3 单链表 2.3.1 定义 2.3.2 术语 2.3.3 类定义 2.3.4 算法:单链表的长度【重点】 2.3.5 算法:按索引号(位序号)查找【重点】 2.3.6 算法:按值查找索引号【重点】 2.3.7 算法:插入 2.3.8 算法:删除 2.3.9 算法:获得前驱 2.4 循环链
陶然同学
2023/02/26
4910
【数据结构】线性表
数据结构 重点详解
该文是关于计算机基础知识的总结,包括基础概念、算法、数据结构等方面。文章还介绍了几个常见的高级技术,如链表、动态规划、分治、贪心算法等。通过这些内容,读者可以更好地理解计算机科学的基础知识,掌握计算机科学的核心思想和方法,并能够应用到实际问题中。
Kindear
2018/01/03
1.6K0
数据结构  重点详解
《王道》数据结构笔记整理2022级_数据结构笔记整理
1.数据:数据是信息的载体,是描述客观事物属性的数、字符以及所有能输入到计算机中并被程序识别和处理的符号的集合。
全栈程序员站长
2022/09/22
3.2K0
《王道》数据结构笔记整理2022级_数据结构笔记整理
相关推荐
数据结构之线性表
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档