精读大话数据结构,陪你拿下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的主要内容,如果未能解决你的问题,请参考以下文章

hadoop eclipse 插件 EP2

精读《dob - 框架使用》

Python爬虫听说你又闹书荒了?豆瓣读书9.0分书籍陪你过五一

《大话数据结构》读后感——第一章

数据结构 EP2 链表 C语言实现单链表及其增删查改

Java 大话数据结构 线性表之单链表