线性表顺序存储代码解释收官之篇
师承陈立臣——抖音:上官可编程
文章目录
前言
下面主要讲解线性表顺序存储代码中的函数功能以及复习函数的调用的基础知识。
上篇我们讲述到了部分知识线性表顺序存储代码解释第一篇
提示:以下是本篇文章正文内容,下面案例可供参考
一、初始化顺序线性表——前提知识补充
我们一开始初始化线性表时,表的长度是0,也就是
L->length=0;
L->length=0;是什么意思呢?结构体指针变量和普通的结构体变量有什么区别呢?
typedef int Status;
typedef类型定义标识符,作用是为一个数据类型或者结构重新定义一个名称;
此处意思是:将整型int关键字重新命名为Status,int和Status
代表的类型是一样的,声明和定义的变量是等价的,都是整型。也就是说:
int a=10;与 Status = 10;是一样的意思。
解释如下:
第一种结构体
要传的参数为结构体指针变量,这个变量为L,所以要使用结构体SqList 中的数据或者变量时,
就得用箭头表示:L->length=0;
(因为这是结构体指针变量,得用箭头表示)
Status InitList(SqList *L)
定义Status类型的函数,函数名为InitList,
参数为结构体指针变量 SqList *L;
{
L->length=0;
return OK;
}
**return OK;**在上篇的代码中提到
#define OK 1
相当于OK=1,OK就是1,return 1;
第二种结构体
要传的参数为结构体整型变量,这个变量为L,所以要使用结构体SqList 中的数据或者变量时,就得用.表示:L.length=0;
(因为不是结构体指针变量,得用.表示)
int InitList(SqList L)
定义int类型的函数,函数名为InitList,
参数为结构体整型变量L;
{
L.length=0;
return OK;
}
有返回值有参数函数
下列代码需要用到printf(),所以包含该文件
#include <stdio.h>
int add(int a, int b)定义整型类型函数,参数为两个整型变量
{
int sum = a + b;
声明整型变量sum,把a+b的值赋给sum。
printf("%d+%d=%d\n", a, b, sum);
输出a的值,b的值,sum的值
return sum;
返回sum的值到main函数中,被调用时可以被赋值,
相当于add(int a,int b)==sum
}
int main()
{
add(1, 2);
调用函数,并把1和2两个参数传给a和b
int sums=add(2,4);
printf("sums=%d\n",sums);
输出的结果为:sums=6;
return 0;
}
int sums = add(2, 4);
在赋值的同时也是调用了函数,所以你会看到2+4=6被输出了
因为add(2,4)函数被调用,执行了add函数中的printf()函数。
无返回值无参数函数
代码执行结果:
搞懂函数调用以及有返回值有参数函数和无返回值无参数函数
理解接下线性表的代码就很简单了
利用以下代码快速理解指针数组函数的综合
#include <stdio.h>
#include <stdlib.h>
void initScores(int *datas,int size)
{
int i;
for (i=0;i<10;i++){
//提示用户输入
printf("请输入第%d个学生的分数",i+1);
//获取用户的输入sacnf
scanf("%d",datas);
if(*datas>100 || *datas< 0)
{
printf("你好恶心,哪里有这种神奇的分数\n");
printf("强制退出该程序,我的程序不给傻逼使用\n");
exit(-1);
}
datas++;
}
}
void printScores(int *datas,int size)
{
int i;
for (i=0;i<size;i++){
printf("第%d个学生的成绩是:%d\n",i+1, *datas++);
}
}
int getMax(int *datas,int size)
{
int max;
int i;
max = *datas;
for (i=0;i<10;i++){
if(max< *datas){
max= *datas;
}
datas++;
}
return max;
}
int getMin(int *datas,int size)
{
int min;
int i;
min=*datas;
for (i=0;i<10;i++){
if(min>*datas){
min=*datas;
}
datas++;
}
return min;
}
float getAverage(int *scores,int size)
{
int i;
int total=0;
float average;
for (i=0;i<size;i++){
total= total+*scores;
}
average=(float)total/10;
return average;
}
void printRet(int data1, int data2, float data3)
{
printf("最高分:%d\n 最低分:%d\n 平均分:%f\n",data1,data2,data3);
}
int main()
{
int scores[10];
int len;
int max ;
int min;
float average;
int *p;
p=&scores[0];
len=sizeof(scores)/sizeof(scores[0]);
//1.初始化数组
initScores(&scores[0],len);//函数调用中,传参数就是一个赋值的过程!实际参数的值,给形式参数
//1.5打印数组
printScores(scores,len);
//2.找到最高分
max =getMax(scores,len);
//3.找到最低分
min =getMin(scores,len);
//4.算出平均分
average=getAverage(scores,len);
//5.输出结果
printRet(max,min,average);
return 0;
}
以上是可执行代码
可以仔细体会里面代码的内容,后续会更新部分指针的知识
二、 函数功能解释
1、初始化顺序线性表——硬性解释
令L->length=0,也就是说L结构体中length的值为0,表的长度为0,就到达初始化表的目的。
typedef struct
{
ElemType data[MAXSIZE]; /* 数组,存储数据元素 */
int length; /* 线性表当前长度 */
}SqList;
/* 初始化顺序线性表 */
SqList *L相当于 struct SqList *L;
Status InitList(SqList *L)
{
L->length=0;
return OK;
}
一样的表达意思
/* 初始化顺序线性表 */
Status InitList(SqList *L)
{
L->length=0;
return OK;
}
int InitList(SqList *L)
{
L->length=0;
return OK;
}
这个代码就过于简单了,也就是整型函数,参数为整型变量ElemType c ;上面都有介绍。函数功能就是输出c变量的值。
Status visit(ElemType c)
{
printf("%d ",c);
return OK;
}
一样的表达意思
Status visit(ElemType c)
{
printf("%d ",c);
return OK;
}
int visit(int c)
{
printf("%d ",c);
return OK;
}
2、若L为空表,则返回TRUE,否则返回FALSE
判断该表的长度是否为0,如果L.length==0 返回值为1,否则返回值为0
/* 初始条件:顺序线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE */
#define ERROR 0
#define TRUE 1
Status ListEmpty(SqList L)
{
if(L.length==0)
return TRUE;
else
return FALSE;
}
一样的表达意思
Status ListEmpty(SqList L)
{
if(L.length==0)
return TRUE;
else
return FALSE;
}
int ListEmpty(SqList L)
{
if(L.length==0)
return TRUE;
else
return FALSE;
}
3、将L重置为空表
也就是将L->length的值等于0,表的长度为0,就可以达到空表的目的,与初始化顺序表的代码是一样的。
/* 初始条件:顺序线性表L已存在。操作结果:将L重置为空表 */
Status ClearList(SqList *L)
{
L->length=0;
return OK;
}
Status InitList(SqList *L)
{
L->length=0;
return OK;
}
4、求表的长度、返回L中数据元素个数
通过传参数ListLength(SqList L),并把结构体中L.length的长度作为返回值,可以在main函数中被调用并赋值,我在上面有介绍。
/* 初始条件:顺序线性表L已存在。操作结果:返回L中数据元素个数 */
int ListLength(SqList L)
{
return L.length;
}
5、获取第i个表中元素的的值
1、下面的代码传了三个参数分别为,结构变量L,整型变量i,整型的指针变量。
如果表的长度L.length==0,意思就是空表,我就不干了,我就return ERROR;也就是return -1,返回这个值有啥用呢,在main函数中调用可以用作判断,返回的值是否等于-1,等于-1我就不干了。
2、i<1 || i>L.length的意思就是,i是指位置,第1个位置的数组是从0开始的,也就是data[0],是第一个位置的元素。i的值不能超过表长,超过表长就会出错,也就是所谓的数组越界,比如表长为10,数组data[11]的值不在表长的范围内,就会出现报错或者乱值。
3、*e=L.data[i-1];这句代码的前提是
if(L.length==0 || i<1 || i>L.length){
return ERROR;
}else{
*e=L.data[i-1];
}
return OK;
然后把data数组的值赋给*e
/* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:用e返回L中第i个数据元素的值,注意i是指位置,第1个位置的数组是从0开始 */
Status GetElem(SqList L,int i,ElemType *e)
{
if(L.length==0 || i<1 || i>L.length)
return ERROR;
*e=L.data[i-1];
return OK;
}
解释一下*e是啥意思, e=L.data[i-1];就是将L.data[i-1]的值赋给e
那为啥L.data[i-1] ,i要减去1呢?因为1≤i≤ListLength(L),这个是初始条件,以及第1个位置的数组是从0开始。
#include <stdio.h>
int main()
{
int *p;//声明指针变量
int a = 10;//定义整型变量a的值为10
p = &a;//把a的地址赋值给p
printf("%d\n", *p);
//*p意思就是取出存放在指针p中地址的值,因为指针p存放的是地址,存放的是a的地址,要取出地址a中的值,也就是10
//
return 0;
}
所以*p是啥意思,下面有继续作了解释
*p:一级指针,表示p所指向的地址里面存放的是一个类型的值
#include <stdio.h>
int main()
{
int *p;
int a = 10;
*p = a;
printf("第一个:%d\n", *p);//10
*p = 100;
printf("第二个:%d\n", *p);//100
return 0;
}
6、获取第i个表中元素的位置
这个函数的功能就是获取某个值所在表中位置。
int LocateElem(SqList L, ElemType e)
{
int i; //定义整型变量 i
if (L.length == 0
//如果表的长度为0,说明是空表,就没有元素获取
return 0;//就返回值为return 0
for (i = 0; i < L.length; i++)
{//遍历表中的所有元素,一个一个元素列举出来进行判断
if (L.data[i] == e)
/*如果表中的第i个元素等于e的值,
(e就是ElemType e,整型变量e,我要传的参数e,
要想知道e这个值的位置是什么。)
那就退出循环,执行returni + 1;*/
break;
}
if (i >= L.length)
/* 如果第i元素的大于等于表的长度,就代表不在表的中,
因为i是从0开始的*/
return 0;
return i + 1;
}
7、在第i个位置插入元素e
/* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L), */
/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert(SqList *L, int i, ElemType e)
{
int k;
if (L->length == MAXSIZE) /* 顺序线性表已经满 */
return ERROR;
//ERROR就是0
if (i < 1 || i > L->length + 1)
/*为什么length要加上1呢?
其实也可以这么写
i > L->length + 1换成i >= L->length
如果第i元素的大于等于表的长度,就代表不在表的中,
因为i是从0开始的。
*/
return ERROR; //ERROR就是0
###############################
# 以上的条件满足后,才做以下的操作 #
###############################
if (i <= L->length) /* 若插入数据位置不在表尾 */
{
如果i <= L->length,就是i小于等于表的长度,就会在L->length插入前面插入就代表,i位置的数据e不在表尾插入,
for (k = L->length - 1; k >= i - 1; k--)
/* 将要插入位置之后的数据元素向后移动一位 */
假设L->length=9,我们要在9这个位置插入元素e,
就得在9前面插入,就是8,所以k = L->length - 1。
L->data[k + 1] = L->data[k];
数据元素都重新赋值,数据元素向后移动一位
}
L->data[i - 1] = e; /* 将新元素插入 */
当我们在在9这个位置插入元素e, 就得在9前面插入,就是8
所以这个数据的L->data[i - 1]==L->data[9-1]=e。
L->length++;
指针++,也就是指针向前移动位置,达到插入数据,表的长度要增加,
所以在这里的意思是L->length的长度增加。
return OK;
}
8、在第i个位置删除元素e
/* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
Status ListDelete(SqList *L, int i, ElemType *e)
{
int k;
if (L->length == 0) /* 线性表为空 */
return ERROR;
if (i < 1 || i > L->length) /* 删除位置不正确 */
return ERROR;
*e = L->data[i - 1];
将要删除的数据元素赋值给*e
if (i < L->length) /* 如果删除不是最后位置 */
{
for (k = i; k < L->length; k++) /* 将删除位置后继元素前移 */
知道要删除数据的元素的位置,将数据重新逐个赋值,
就达到删掉要删掉位置上的元素。
*****************
* 0 1 2 3 4 * (第一个数组的下标是从0开始)
* 5 6 7 8 9 * (第一个数组存放的元素是5开始)
*****************
因为条件删除不是最后位置,所以假如
删除7,第三个元素,k=i=3,数据是L->data[k - 1]
L->data[2]=7,L->data[k]=L->data[3]=8
重新赋值:L->data[2]=L->data[3]=8;
所以元素7就被删除了。
L->data[k - 1] = L->data[k];
}
L->length--;
删除的元素,表的长度就要减少。
return OK;
}
9、遍历元素
总体就是对 visit(L.data[i])函数遍历调用输出c的值
没啥好讲的,这层次还不明白的话,你的基础还是得继续抓抓了
/* 初始条件:顺序线性表L已存在 */
/* 操作结果:依次对L的每个数据元素输出 */
Status ListTraverse(SqList L)
{
int i;
for (i = 0; i < L.length; i++)
visit(L.data[i]);
// visit();这个函数在前面已经讲过了,就不再赘述了
printf("\n");
return OK;
}
10、将所有的在线性表Lb中但不在La中的数据元素插入到La中
/*将所有的在线性表Lb中但不在La中的数据元素插入到La中*/
void unionL(SqList *La, SqList Lb)
{
int La_len, Lb_len, i; //定义三个整型变量
ElemType e; //e也是整型变量
/*声明与La和Lb相同的数据元素e*/
函数调用,将要求长度的表放进ListLength()中,得到的返回值
就是表的长度
La_len = ListLength(*La); /*求线性表的长度 */
Lb_len = ListLength(Lb);/*求线性表的长度 */
for (i = 1; i <= Lb_len; i++)
{
GetElem(Lb, i, &e);
/*
取Lb中第i个数据元素赋给e
在将e的值作为LocateElem(*La, e)的参数
进行判断La中是否有和e相同数据元素
LocateElem(*La, e)
*/
if (!LocateElem(*La, e))
/*
La中不存在和e相同数据元素
*/
如果La中不存在和e相同数据元素
那么就进行插入。
ListInsert(La, ++La_len, e); /*插入*/
}
}
三:源码展示
#include "stdio.h"
/*
include 称为文件包含命令,其意义是把尖括号""或引号<>内指定的文件包含到本程序中,
成为本程序的一部分。被包含的文件通常是由系统提供的.
而stdio为standard input output的缩写,意为“标准输入输出”
在程序要调用输入scanf()或printf()输出函数,必须包含stdio.h文件
*/
//下列也是同样的意思
#include "stdlib.h"
#include "math.h"
#include "time.h"
#define OK 1 //宏定义,就是定义ok=1,当后面调用ok的时候,ok就相当于1;
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20
/* 存储空间初始分配量,
宏定义,就是定义MAXSIZE=20,当后面比较MAXSIZEk的时候,MAXSIZE就相当于20 */
typedef int ElemType; /* ElemType类型根据实际情况而定,这里假设为int */
/*
typedef类型定义标识符,作用是为一个数据类型或者结构重新定义一个名称;
此处意思是:将整型int关键字重新命名为ElemType,int和ElemType
代表的类型是一样的,声明和定义的变量是等价的,都是整型。也就是说:
int a=10;与 ElemType a = 10;是一样的意思。
*/
typedef struct
{
ElemType data[MAXSIZE]; /* 数组,存储数据元素 */
int length; /* 线性表当前长度 */
} SqList;
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
Status visit(ElemType c)
{
printf("%d ", c);
return OK;
}
/* 初始化顺序线性表 */
Status InitList(SqList *L)
{
L->length = 0;
return OK;
}
/* 初始条件:顺序线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE */
Status ListEmpty(SqList L)
{
if (L.length == 0)
return TRUE;
else
return FALSE;
}
/* 初始条件:顺序线性表L已存在。操作结果:将L重置为空表 */
Status ClearList(SqList *L)
{
L->length = 0;
return OK;
}
/* 初始条件:顺序线性表L已存在。操作结果:返回L中数据元素个数 */
int ListLength(SqList L)
{
return L.length;
}
/* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:用e返回L中第i个数据元素的值,注意i是指位置,第1个位置的数组是从0开始 */
Status GetElem(SqList L, int i, ElemType *e)
{
if (L.length == 0 || i < 1 || i > L.length)
return ERROR;
*e = L.data[i - 1];
return OK;
}
/* 初始条件:顺序线性表L已存在 */
/* 操作结果:返回L中第1个与e满足关系的数据元素的位序。 */
/* 若这样的数据元素不存在,则返回值为0 */
int LocateElem(SqList L, ElemType e)
{
int i;
if (L.length == 0)
return 0;
for (i = 0; i < L.length; i++)
{
if (L.data[i] == e)
break;
}
if (i >= L.length)
return 0;
return i + 1;
}
/* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L), */
/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert(SqList *L, int i, ElemType e)
{
int k;
if (L->length == MAXSIZE) /* 顺序线性表已经满 */
return ERROR;
if (i < 1 || i > L->length + 1) /* 当i比第一位置小或者比最后一位置后一位置还要大时 */
return ERROR;
if (i <= L->length) /* 若插入数据位置不在表尾 */
{
for (k = L->length - 1; k >= i - 1; k--) /* 将要插入位置之后的数据元素向后移动一位 */
L->data[k + 1] = L->data[k];
}
L->data[i - 1] = e; /* 将新元素插入 */
L->length++;
return OK;
}
/* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
Status ListDelete(SqList *L, int i, ElemType *e)
{
int k;
if (L->length == 0) /* 线性表为空 */
return ERROR;
if (i < 1 || i > L->length) /* 删除位置不正确 */
return ERROR;
*e = L->data[i - 1];
if (i < L->length) /* 如果删除不是最后位置 */
{
for (k = i; k < L->length; k++) /* 将删除位置后继元素前移 */
L->data[k - 1] = L->data[k];
}
L->length--;
return OK;
}
/* 初始条件:顺序线性表L已存在 */
/* 操作结果:依次对L的每个数据元素输出 */
Status ListTraverse(SqList L)
{
int i;
for (i = 0; i < L.length; i++)
visit(L.data[i]);
printf("\n");
return OK;
}
/*将所有的在线性表Lb中但不在La中的数据元素插入到La中*/
void unionL(SqList *La, SqList Lb)
{
int La_len, Lb_len, i;
ElemType e; /*声明与La和Lb相同的数据元素e*/
La_len = ListLength(*La); /*求线性表的长度 */
Lb_len = ListLength(Lb);
for (i = 1; i <= Lb_len; i++)
{
GetElem(Lb, i, &e); /*取Lb中第i个数据元素赋给e*/
if (!LocateElem(*La, e)) /*La中不存在和e相同数据元素*/
ListInsert(La, ++La_len, e); /*插入*/
}
}
int main()
{
SqList L;
SqList Lb;
ElemType e;
Status i;
int j, k;
i = InitList(&L);
printf("初始化L后:L.length=%d\n", L.length);
for (j = 1; j <= 5; j++)
i = ListInsert(&L, 1, j);
printf("在L的表头依次插入1~5后:L.data=");
ListTraverse(L);
printf("L.length=%d \n", L.length);
i = ListEmpty(L);
printf("L是否空:i=%d(1:是 0:否)\n", i);
i = ClearList(&L);
printf("清空L后:L.length=%d\n", L.length);
i = ListEmpty(L);
printf("L是否空:i=%d(1:是 0:否)\n", i);
for (j = 1; j <= 10; j++)
ListInsert(&L, j, j);
printf("在L的表尾依次插入1~10后:L.data=");
ListTraverse(L);
printf("L.length=%d \n", L.length);
ListInsert(&L, 1, 0);
printf("在L的表头插入0后:L.data=");
ListTraverse(L);
printf("L.length=%d \n", L.length);
GetElem(L, 5, &e);
printf("第5个元素的值为:%d\n", e);
for (j = 3; j <= 4; j++)
{
k = LocateElem(L, j);
if (k)
printf("第%d个元素的值为%d\n", k, j);
else
printf("没有值为%d的元素\n", j);
}
k = ListLength(L); /* k为表长 */
for (j = k + 1; j >= k; j--)
{
i = ListDelete(&L, j, &e); /* 删除第j个数据 */
if (i == ERROR)
printf("删除第%d个数据失败\n", j);
else
printf("删除第%d个的元素值为:%d\n", j, e);
}
printf("依次输出L的元素:");
ListTraverse(L);
j = 5;
ListDelete(&L, j, &e); /* 删除第5个数据 */
printf("删除第%d个的元素值为:%d\n", j, e);
printf("依次输出L的元素:");
ListTraverse(L);
//构造一个有10个数的Lb
i = InitList(&Lb);
for (j = 6; j <= 15; j++)
i = ListInsert(&Lb, 1, j);
unionL(&L, Lb);
printf("依次输出合并了Lb的L的元素:");
ListTraverse(L);
return 0;
}
三、总结
线性表顺序存储就解释到这,后续的线性表链式存储以及其他的数据结构,几乎都是同样的意思,本人希望本文能够教会大家如何看代码,看得懂代码,知道代码表达的意思,感谢支持。
以上就是今天要讲的内容,本人知识有限,难免会有错,写的也难免不够严谨,你若发现不对,或看了解释还不懂,欢迎在评论区提出。