精读大话数据结构,陪你拿下45分 EP2
Posted fanzhaokai0420
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了精读大话数据结构,陪你拿下45分 EP2相关的知识,希望对你有一定的参考价值。
上一期我们学习了数据结构的基本知识,那么这次就要进入实战啦!
回顾:
什么是线性表?
内存中以顺序存储的表。
这里我们就要以线性表讲起,来实现各种接口函数
线性表基本形式
#define MAXSIZE 20
//定长顺序表
//方便我们的删改
typedef int SQdateType;
//便于更换顺序表的存储元素类型
struct SeqList
{
int arr[MAXSIZE]; //这个是最大长度,就是总的最大存储容量
int length; //当前表长,
};
typedef struct SeqList List;
最大长度可以理解为我们向内存申请的空间大小
表长理解为实际表的长度,也就是说这部分空间我们用不完。
表的初始化
void InitList(List* PL) // 初始化顺序表
{
memset(PL->arr, 0,sizeof(SQdateType)*MAXSIZE);
PL->length = 0;
/*memset用法,地址,要修改的值,要修改的总长度*/
}
我们这里采取memset库函数来进行初始化,开辟一块大小为MAXSIZE的空间。
要注意的是表的长度指的是 PL->length表长,而不是所占空间大小
表的遍历展示
void ShowList(List* PL)
{
for (int i = 0; i < PL->length; i++)
{
printf("%d ", PL->arr[i]);
}
printf("\\n");
}
表的头尾删改
头插尾插是我们常见的表的操作,下面我们来具体分析
1 尾插法
void SeqListPushBack(List *PL, int n)// 导入顺序表指针,和插入尾部的数
{
if (PL->length >= MAXSIZE)
{
printf("顺序表已满,不可插入;");
}
else
{
PL->arr[PL->length] = n;
/*为什么直接就是length不用考虑length为0?
因为:数组的下标从0开始的*/
PL->length++;
printf("尾插完毕\\n");
}
}
尾插法很容易理解,就是在表不满的前提下,把表延长一位并附上我所要插入的值
2 首插法
void SeqListPushFront(List* PL, int n)//头插法
{
if (PL->length >= MAXSIZE)
{
printf("顺序表已满,不可插入;");
}//经典判断不解释
else
{
for (int i = PL->length - 1; i >= 0; i--)
{
PL->arr[i + 1] = PL->arr[i];//一直往后放
}
PL->arr[0] = n;
PL->length++;
printf("头插完毕\\n");
}
}
首插法又称头插法,顾名思义,是从表的首部插入元素
这样操作在表未满的前提下完成两个操作
(1)表长加一,将所有的元素都往后移动一位
(2)把我要插入的元素放到首位
往后移动这个操作很好理解,将指针定位在表的最后一个元素,将他的值放在后一个元素中,循环往复直到指针指向头元素。
3 尾删法
void SeqListPopback(List* PL) //尾删
{
if (PL->length ==0)
printf("该位置没有数据\\n");
else
{
PL->arr[PL->length] = 0;
PL->length--;
printf("尾删结束\\n");
}
}
尾删法则更好理解,只需将表缩减一位即可
4 首删法
void SeqListPopFront(List* PL)//首删
{
if (PL->length == 0)
printf("该位置没有数据\\n");
else
{
for (int i = 0; i<PL->length-1; i++)
{
PL->arr[i] = PL->arr[i + 1];
}
PL->length--;
printf("首插结束\\n");
}
}
首删法同样简单,只需要除了第一位外,依次向前移动一位,直到最后一位
表的连续赋值
void ContinueInitList(List* PL)
{
int n;
printf("请输入你要初始化的个数\\n");
scanf_s("%d", &n);
for (int i = 0; i < n; i++)
{
scanf_s("%d", &PL->arr[i]);
PL->length++;
}
}
顾名思义,将表连续初始化,用于衔接前面的初始化使其快速赋值
获得表中元素
void GetElem(List* PL, int i, int*e) //将线性表中第i个元素赋值给e
{
if (i <= PL->length && i > 0) // 0<i<=length
{
*e = PL->arr[i - 1];
}
else
printf("输入有误");
}//这里传地址是因为形参地址开辟的空间小,避免出现压栈的为题
获得方法较为简单,就是在 i不越界的前提下,将第i个元素的值赋值给我们传入的变量。
但是既然不牵扯到改变表,我们为什么还要传递表的指针呢?
这就牵扯到啊函数的栈帧问题了,我们在调用函数时,会从栈区开辟一块空间,并在这块空间里面开辟形参接收我们传过来的实参。在这种情况下,如果我们的表内存过大很容易造成形参过大,使得内存崩塌,但我们如果传递指针,则只会开辟4个字节的形参从根本上解决压栈问题。
判断元素是否存在
int LocateElem(List* PL, int e)//找线性表与e相等的元素,找到返回序号,没找到返回0
{
for (int i = 0; i < PL->length; i++)
{
if (PL->arr[i] == e)
return i + 1;
}
return 0;
}
这里就是遍历表,如果有和我们要找的值相同的就返回我们下标加一,也就是返回我们的元素序号。
表中插入
void ListInsert(List* PL, int i, int e) //表中第i个元素的后面插入e
{
if (i <= 0 || i > PL->length)
{
printf("输入有误\\n");
}
else
{
for (int j = PL->length - 1;j > i-1; j--)
{
PL->arr[j + 1] = PL->arr[j];
}
PL->arr[i] = e;
PL->length++;
printf("插入完毕!\\n");
}
}
表中插入可以理解尾一种变相的头插法。
我们还是在表不满的前提下完成两个操作
(1)把我们插入的位置之后的全部向后移动一个单位
这样做会空出一个位置
(2)把待插入的元素插入到位置
在移动操作时我们先将指针定位在表的末端即 数组下标为表长减一的值,将他们依次后移直到移动到我们要添加元素的下一位。
最后不要忘了再把length表长增加一个哦!
删除表中元素
void ListDelete(List* PL,int i, int *e) //删除表中第i个元素,并用e返回其值
{
if (i <= 0 || i > PL->length)
{
printf("输入序号有误\\n");
}
else
{
*e = PL->arr[i - 1]; //序号数减一等于实际数组下标
for (int j = i - 1; j < PL->length - 1; j++)
{
PL->arr[i] = PL->arr[i + 1];
}
printf("删除完毕\\n");
}
}
这里是头删法的一个变种,从这个元素开始依次将后面的元素向前放一个,直到表的末端
还是不要忘了减少表长哦
这里我们顺序表的接口函数就结束啦,下一次我们就要来分析链表的接口函数,期待与大家再次见面!!
参考教材:
《大话数据结构》 --风清杨老师
《数据结构(c语言)》--严蔚敏
以上是关于精读大话数据结构,陪你拿下45分 EP2的主要内容,如果未能解决你的问题,请参考以下文章