2.2 线性表的基本操作

目录

一、概述

二、注意

2.1 五点注意

2.2 引用描述 

2.3 实现基本操作原因

2.4 总结

三、线性表的操作

3.01 初始化

3.02 销毁

3.03 清除

3.04 判空

3.05 长度计算​编辑

3.06 获取元素

3.07 查找和搜索

3.08 求一个元素的前趋

3.09 获得一个后继元素

3.10 插入一个元素

​3.11 删除一个元素

3.12 遍历每一个元素


一、概述

需要对线性表实现哪些基本操作(基本运算)?

数据结构三要素——数据的运算。

(1)首先,需要实现的两个最基本操作:

  • 初始化一个线性表。
  • 销毁一个线性表。

实现了线性表从无到有和从有到无这样的两个过程。

(2)创建和销毁是两个最基本操作,主要做的工作就是

  • 分配内存空间、释放内存空间
  • 更改一些必要的信息。

(3) 插入和删除

插入函数的参数有3个:

  • 第1个参数L:传入线性表L。
  • 第2个参数i:在第i个位置插入元素。
  • 第3个元素e:具体要插入元素的值。

 (4)查找的两种基本操作,查询某一个数据元素。

  •  按值查找:给定一个元素e的值,然后在线性表L中查找,该线性表中,有没有哪个数据元素和我们传入的这个参数e是相同的。
  • 按位查找:传入一个参数i,i指明想找的是线性表中的第几个元素。

(5)其他常用操作

下面定义三个函数,传入的参数都是一个线性表。

二、注意

2.1 五点注意

(1)学任何一个数据结构时,基本上对于数据结构的操作:创建、销毁、增删改查。

  • 增加一个数据元素
  • 删除一个数据元素
  • 改变一个数据元素的值
  • 查询某个数据元素

大家在学习之后的数据结构时,也可以自己思考一下,对于某一种特定数据结构的创建、销毁、增删改查应该怎么实现。

(2)C语言当中,如果定义一个函数。

  • 需声明一个函数名。
  • 在函数名之后需要声明参数列表,包括参数名和参数的具体类型。

在上面描述这些基本操作时,并没有指明具体的参数类型到底是什么?

  • 这个地方给出的这种函数接口,具有抽象性的。
  • 所以,在描述基本操作时,并没有指明这个参数的具体类型。
  • 只有用代码来实现这些基本操作时,才需真正的关心这些参数具体是什么类型。

(3)实际开发中(或做题时),可根据实际需求,再定义其他的基本操作。

比如:如果更改某一个数据元素操作很常用,就可把更改一个数据元素定义为一个基本操作。

(4)在这儿给出的这些函数名、参数名,这些命名方式,参考严蔚敏版《数据结构》,很多高校指定参考教材都是严蔚敏版的。

做题时,并不一定要完全按照他这儿给的这种命名方式。

不需要太教条化,命名的这些函数,还有这些变量,它的名字需要具有可读性。

例如:

  • DestroyList:销毁一个表。
  • 你不能说你自己定义的销毁操作,你取一个函数名叫a,谁知道你的a是干嘛的。
  • 在答题时,使用这个地方推荐的这些命名方式,肯定是改卷老师很喜欢看到的。

(5)有的函数,有的基本操作,里边传入的这个参数是&引用类型,这是C++的写法。

什么时候需要传入这种引用型的参数呢?

如果对参数的修改结果需要带回来的话,就需要传入这种引用型的参数。

引用类型是C++里边的东西,所以大家在运行这段程序的时候,需要选C++在线工具,只有C++的编译器才可以支持,C语言是不支持这种引用类型的。

(6) 总结

2.2 引用描述 

(1)什么叫做把修改的结果没有带回来?

test函数对x的值虽然进行修改,但这个修改结果没有带回到main函数。背后原因:

  • 在main函数里边定义一个变量x,初始值为1。
  • 调用test函数时,test函数里的x是main函数里边这个x的一个复制品。

两个变量虽然都叫x,但在内存中,其实是两份不同的数据。

  • test函数中把x的值改成1024,改的其实是复制品中的数据。
  • test运行结束又回到main函数后,该出打印出的x值其实还是原本的x值,依然是1。

(2)再来看一个具体的例子,什么叫做把修改的结果带回来?

把这个参数改成引用类型,也就在参数名前面加一个引用符号。

如果把参数改成引用类型,那么test函数中对参数的修改,就被带回到main函数中。

简单理解:

  • main函数里边定义一个变量x,然后这个变量x作为参数传给了test函数。
  • 由于test函数中定义形参是引用类型,test函数中,操作参数和main函数中的x是同一份数据。
  • 在test中对x修改,也会影响到main函数里的这个x的值。

通过两个例子明白:什么叫需要把对参数的修改结果给带回来。

 (3)插入操作时,加引用符号。

  • 在此函数中,需要修改线性表L的具体内容,并希望把这个修改的效果给带回去,所以这个地方要加引用符号。
  • 为什么这些地方需要加引用符号,而这些地方又没有加,这个是很重点的东西,一定要理解大家才能写出没有错误的代码。

2.3 实现基本操作原因

现在的项目一般都是大型项目,都需要一个很大的团队,合作编程。

如果你是定义一个数据结构的这个定义者,你定义的数据结构,肯定是需要能够让你的队友们,能够很方便使用。

定义了一个数据结构后,还需要给你的队友们提供一些很方便易用的函数,把这些基本操作用函数的方式给封装起来。

当把这些基本操作,封装成函数之后,就可避免重复的工作。

因为这些基本操作都是很常用的。

你把它封装成函数之后,以后每一次要用你不需重写一遍代码,只需调用一个函数就可解决。

学习时经常Why思考:经常只会关注how,并不会去思考为什么要这么做?

  • 其实想明白为什么这一点是很重要的。
  • 只有想明白为什么做一件事?做一件事的意义是什么?
  • 在学习做这件事的时候,才会更有动力,更加积极主动。

2.4 总结

(1)线性表(是一种数据结构)的逻辑结构,理解起来都很简单。

(2)位序:一个数据元素在线性表当中第几个位置,也就是说位序是从1开始的。

  • 程序数组的下标:从0开始。
  • 用数组实现一个线性表时,一定要注意审题。

(3)需要对线性表实现哪些基本操作、基本的运算。对于所有数据结构来说,最重要最核心的基本运算(操作):创建、销毁、增删改查。

(4)参数什么时候需要使用引用类型,这个一定要理解清楚。

(5)函数的命名,还有变量的命名。

  • 一定要有可读性。
  • 让其他人看一眼就知道你的函数,你的这个变量到底是要干什么的。

三、线性表的操作

3.01 初始化

线性表的初始化:构造一个空的线性表后,计算机内存当中就有这个线性表了,就可以往这个线性表当中存储数据了。

3.02 销毁

线性表的销毁:

  • 没有线性表,那就没法去销毁了。
  • 必须有一个已经存在的线性表,我们才可以销毁它。
  • 销毁:从内存当中把这个线性表这个删除了,内存当中再没有这个线性表。

      3.03 清除

      如果这个线性表当中有若干个元素的话,我们将这若干个元素都清除掉。

      清除一个线性表和销毁一个线性表有点儿类似:

      • 销毁一个线性表:线性表本身在内存当中不存在。销毁是连表本身都没有。
      • 清除线性表:这个线性表还在内存当中,但是该表中没有元素,把这个表变成一个空表。表本身还在,那个位置还在。

      3.04 判空

      n=0,就是空表,n是元素的个数。

      判断一个线性表是否为空:判断一下这个线性表当中是否有元素。

      • 如果没有元素,元素的个数为零,那就是空表。
      • 里头没有元素啊,元素的个数为零。
      • 是的话,这个操作的结果就得到一个真。
      • 不是的话,我们就得到一个假。

      判断当前表里头是否有元素,没有元素就是为真。

      判断是否为空,没有元素就是空。

      3.05 长度计算

      线性表的长度:这个线性表当中元素的个数n。

      能够这个数出来,线性表当中到底有几个元素,元素个数。

      3.06 获取元素

      线性表L当中,来获取一个元素(element)。

      在线性表的第i个位置上,来取第i个元素。

      为什么要≤线性表的长度?

      • 如果线性表中,有n个元素的话,只能取第1个到第n个。
      • 没有第零个元素,-1个元素,没有第n+1个元素。
      • 只有n个元素,从一号位置到n号位置,n个元素。
      • 所以,要取的这个元素,只能是在1≤i≤n的范围内。

      初始条件:

      • 有线性表L存在。
      • 告诉你一个合适的位置,我们要把这个位置上的元素取出来(Get)。

      取出来放在,引用型的变量e里头。

      3.07 查找和搜索

      这个操作,是来完成查找和定位的。

      在这个线性表当中,来查找与这个e,e是一个具体的值。

      compare()是一个判定函数,一个判定条件,它表示这个判定条件到底是一个什么关系。

      • e满足一个条件,这个条件用这样的一个判定函数来表示。
      • 该判定函数可能是相等:找和元素e相等的元素。
      • 找大于元素e的元素。
      • 找小于元素e的元素。
      • 具体是><=,或者还有其他的条件,由compare()函数来确定。

      具体的问题可能不一样。这里只是个抽象的数据模型,具体的问题再具体去分析。

      • 如果找到了,那我们就返回第一个找到的这个元素。
      • 如果存在这样的元素,我们就返回的结果呢,就是0。
      • 这就是咱们说的定位、查找,查找满足我们规定的这个条件。

      满足进行比较的这个条件,把它找回来、找出来。


        然在这里没有定义,更改某一个数据元素的值,这样的基本操作。

        改的操作,在改之前也需要查到想要改的那个数据元素。

        所以,其实改操作的第一步也是查,需要先找到想要改的那个数据元素。 

        最核心的基本操作:创建、销毁、增删改查。

        其他基本操作:为了方便编程而实现的。

        3.08 求一个元素的前趋

        前置条件:

        • 线性表L已经存在了有这样一个线性表。
        • 告诉我们一个元素。

        3.09 获得一个后继元素

        如果当前元素不是最后一个,就获得它的后继。

        3.10 插入一个元素

        (1)对线性表的插入和删除操作,就是增加一个数据元素和删除一个数据元素。

        在1~n中,有n个元素,规定一个插入位置:

        • 可以插入在第一位,插在第一个位置。
        • 也可以插在第二个位置,第三个位置。
        • 也可以插在最后一个元素之后,也就是点n+1的位置。

        在1~n位置插入是合法的,其他的插入位置是不合法的。

        3.11 删除一个元素

        3.12 遍历每一个元素

        具体的这个访问和操作是做什么是不确定的。例如:

        • 每一个元素我都输出它的某个值,这个访问可能是输出。
        • 每一个元素,从头到尾所有元素修改一下。
        • ……………………

        还有一些复杂的操作,可以用这些简单的操作去完成。

        #define list_size 10 #define increment 5 #define ok 1 #include<stdlib.h> #include<stdio.h> #include<string.h> typedef struct{ int *elem; int length; int listsize;}sqlist; int initlist(sqlist &L)//构造一个空的线性表 { L.elem=(int *)malloc(list_size*sizeof(int)); if(!L.elem) printf("申请空间失败\n"); L.length=0; L.listsize=list_size; return ok; } int listinsert( sqlist &L, int i, int e )//插入 { int *p,*q,*newbase; if(i<1||i>L.length+1) printf("位置不合法\n"); if(L.length>=L.listsize) {newbase=(int *)realloc(L.elem,(L.listsize+increment)*sizeof(int));//扩容 if(!newbase) printf("扩容失败\n"); L.listsize+=increment;} q=&(L.elem[i-1]);// q 指示插入位置 for(p=&(L.elem[L.length-1]);p>=q;--p) *(p+1)=*p;// 插入位置及之后的元素右移 *q=e; // 插入e ++L.length;// 表长增1 return ok; } int ListDelete(sqlist &L, int i, int &e) //删除数据 { if ((i < 1) || (i > L.length)) printf("位置不合法\n"); int *p=&(L.elem[i-1]); // p 为被删除元素的位置 e = *p; // 被删除元素的值赋给 e int *q = L.elem+L.length-1; // 表尾元素的位置 for (++p; p <= q; ++p) *(p-1) = *p; // 被删除元素之后的元素左移 --L.length; // 表长减1 return ok; } int Listlength(sqlist L) //长度 { int *p=L.elem; //判断线形表是否存在 while(p) { return (L.length); } } int GetElem(sqlist L, int i,int &e) //取元素 { if(i<1 || i>L.length) printf("不存在此元素\n"); else { e=L.elem[i-1]; return e; } } void MergeList(sqlist La, sqlist Lb, sqlist &Lc;)//将非递减的有序表 La 和 Lb 归并为 Lc { initlist(Lc); // 构造空的线性表 Lc int i ,j ;i=j= 1; int k = 0; int La_len = Listlength(La); int Lb_len = Listlength(Lb); int ai,bj; i= j = 1, k = 0; GetElem(La, i, ai); GetElem(Lb, j, bj); if (ai <= bj) // 将 ai 插入到 Lc 中 { listinsert(Lc, ++k, ai); ++i; } else { // 将 bj 插入到 Lc 中 listinsert(Lc, ++k, bj); ++j; } while (i <= La_len) // 当La不空时 { GetElem(La, i++, ai); listinsert(Lc, ++k, ai); } // 插入 La 表中剩余元素 while (j <= Lb_len)// 当Lb不空时 { GetElem(Lb, j++, bj); listinsert(Lc, ++k, bj); } // 插入 Lb 表中剩余元素 } void printlist(sqlist &L)//打印 { int i; printf("\n$$$$$$$$$$$$$$$$$"); printf("\n顺序表的元素为:\n"); for(i=0;i<L.length;i++) printf("%d ",L.elem[i]); printf("\n$$$$$$$$$$$$$$$$$\n"); return; } main( ) { int i,j,n1,n2,e; sqlist La,Lb,Lc; initlist(La); printf("请输入顺序表La长度:"); scanf("%d",&La;.length); printf("请输入顺序表La的元素:"); for(n1=0;n1<La.length;n1++) scanf("%d",&La;.elem[n1]); printlist(La); printf("\n"); printf("请输入插入元素的位置:"); scanf("%d",&i); printf("请输入新元素:"); scanf( "%d", &e); listinsert(La,i,e ); printlist(La); printf("请输入删除第几个元素\n"); scanf("%d",&j); ListDelete(La,j,e); printlist(La); initlist(Lb); printf("请输入顺序表Lb长度:"); scanf("%d",&Lb;.length); printf("请输入顺序表Lb的元素:"); for(n2=0;n2<Lb.length;n2++) scanf("%d",&Lb;.elem[n2]); printlist(Lb); printf("合并\n"); initlist(Lc); MergeList(La,Lb,Lc); printlist(Lc); return 0; }
        以下是 C 语言线性表基本操作代码: #include <stdio.h> #include <stdlib.h> #define MAXSIZE 100 // 线性表的最大长度 typedef int ElemType; // 定义线性表元素类型为整型 typedef struct { ElemType data[MAXSIZE]; // 存储线性表元素的数组 int length; // 线性表的当前长度 } SqList; // 顺序存储结构的线性表 // 初始化线性表 void InitList(SqList *L) { L->length = 0; // 线性表长度为0 } // 判断线性表是否为空 int ListEmpty(SqList L) { return L.length == 0; } // 获取线性表长度 int ListLength(SqList L) { return L.length; } // 获取线性表中指定位置的元素 int GetElem(SqList L, int i, ElemType *e) { if (i < 1 || i > L.length) { return 0; // i值不合法 } *e = L.data[i - 1]; // 将第i个元素的值赋给e return 1; } // 在线性表中查找指定元素的位置 int LocateElem(SqList L, ElemType e) { for (int i = 0; i < L.length; i++) { if (L.data[i] == e) { return i + 1; // 返回元素在线性表中的位置 } } return 0; // 没有找到元素 } // 在线性表中插入元素 int ListInsert(SqList *L, int i, ElemType e) { if (i < 1 || i > L->length + 1) { return 0; // i值不合法 } if (L->length >= MAXSIZE) { return 0; // 线性表已满 } for (int j = L->length; j >= i; j--) { L->data[j] = L->data[j - 1]; // 将第i个元素及之后的元素后移 } L->data[i - 1] = e; // 将新元素插入到第i个位置 L->length++; // 线性表长度加1 return 1; } // 在线性表中删除元素 int ListDelete(SqList *L, int i, ElemType *e) { if (i < 1 || i > L->length) { return 0; // i值不合法 } *e = L->data[i - 1]; // 将第i个元素的值赋给e for (int j = i; j < L->length; j++) { L->data[j - 1] = L->data[j]; // 将第i个元素之后的元素前移 } L->length--; // 线性表长度减1 return 1; } // 打印线性表中的所有元素 void PrintList(SqList L) { for (int i = 0; i < L.length; i++) { printf("%d ", L.data[i]); } printf("\n"); } // 测试线性表基本操作 int main() { SqList L; InitList(&L); ListInsert(&L, 1, 1); ListInsert(&L, 2, 2); ListInsert(&L, 3, 3); ListInsert(&L, 4, 4); ListInsert(&L, 5, 5); printf("线性表中的元素为:"); PrintList(L); int e; GetElem(L, 3, &e); printf("线性表中第3个元素为:%d\n", e); printf("元素2线性表中的位置为:%d\n", LocateElem(L, 2)); ListDelete(&L, 4, &e); printf("删除线性表中第4个元素后,线性表中的元素为:"); PrintList(L); printf("线性表的长度为:%d\n", ListLength(L)); return 0; }
        评论
        添加红包

        请填写红包祝福语或标题

        红包个数最小为10个

        红包金额最低5元

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

        打赏作者

        小李在进步er

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

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

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

        打赏作者

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

        抵扣说明:

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

        余额充值