关于链表的一些总结(上)

六月份了,步入考试周,复习有点晕头转向,总结一次拖一次,哎,难顶,只能后边加油补,不过也算是一直保持练习,后边继续温习,也算好事。这次先对普通顺序表(定长以及不定长),单链表,循环链表,双向链表以及静态链表(这里我还写了一个静态链表的小改造,改的也不多,做了一个不定长的,hhh)


先是顺序表,定长就不说了,下边是结构体

typedef struct List
{
	int *elem;
	int len;
	int size;
}List,* PList;

结构体,这里elem是接收后边创建动态内存的指针的,len保存当前数组有效元素的个数,size是存储当前数组尺寸大小的,方便后边数组满后扩容,这里,当前实例,初次初始化列表大小为十个整型大小,之后表满时,每次扩容为2倍,所以,内部有判满以及扩容函数。然后此表实现了一些常用的插入、删除、获得表长,打印表内容
清除数据、摧毁表相应操作,下面附上头文件,实现代码不做说明。


void InitList(PList pl);//初始化顺序表

bool Isempty(PList pl);//判断是否空

static bool Isfull(PList pl);//内部使用表是否满

bool Insert(PList pl,int val);//插

bool Delete_val(PList pl,int val);//删除第一个Val值

bool Delete_pos(PList pl,int pos);//删除pos位置值

int Getlenth(PList pl);//获得长度

void Show(PList pl);//打印表内容

void Clear(PList pl);//清除数据

void Destory(PList pl);//摧毁表


这里要说的一点就是清除数据,代表当前表中的数据全都作废,所以只需要修改结构体中列表有效长度为0即可,摧毁表需要释放掉动态内存指针的空间,并且释放掉之后切记需要将该指针置为空指针,防止出现野指针。


接下来是链表,此处均为带头结点链表


单链表结构体如下:

typedef struct Node
{
	int data;
	struct Node *next;
}Node,* PSList;

一个数据域,一个指针域,数据域存数据,指针域存下个结点的地址,这里说一下删除操作,
在这里插入图片描述
删除二号节点,需要通过他的前驱节点来删除自身(这里指的是真实删除某个节点),将前驱节点的next指针赋值为二号节点的next指针值,然后释放二号节点内存空间即可,所以内部拥有查找前驱节点的函数(总结至此处才想起来顺序表忘记了查找操作,不过太过简单,所以就没有进行后续的补充),这里注意在查找前驱节点时候,要删除的节点可能是第一个,所以他的前驱即为头节点,所以查找的开头应该初始化为头节点进行查找,实现如下

static Node *SearchPri(PSList pl,int val)//查找前驱结点
{
	assert(pl != NULL);
	for(Node *p=pl;p->next!=NULL;p=p->next)
	{
		if(p->next->data == val)
		{
			return p;
		}
	}
	return NULL;
}

成功返回指针,失败返回空指针。


其次是插入(貌似按照顺序应该先说插入,hhh,但是无所谓了)
在这里插入图片描述
删除时,在断开1,2节点的连接同时要把2节点地址赋值给新节点3的next,然后再把3节点地址赋值给1节点next,若操作反之,先把3赋值给1,那么2就会丢失地址,一会造成数据丢失,二会造成内存泄漏,在代码中实现如下:

bool Insert(PSList pl,int val)//插(头插)
{
	assert(pl != NULL);
	Node *p = (Node *)malloc(sizeof(Node));
	p->data = val;
	p->next = pl->next;
	pl->next = p;
	return true;
}

代码考虑还不是很周到,仅作参考,具体实现不做说明,同顺序表相同,支持插入删除查找,获取长度,打印表,清除摧毁相应操作。


循环单链表,实现和普通单链表几乎无差异,仅仅是循环单链表中,最后一个节点的next不是NULL,而是头节点的地址,这样当走到链表最后一个节点,再往后走,又会回到头节点,形成循环,所以循环单链表中的遍历整个链表操作需要注意,循环的判断不是遇到NULL循环停止,而是再次遇到头节点停止(由于实现和普通单链表差不多,这里就不多说明)


双向链表,双向链表,其实和单向链表差不多,就是设计微微有所差别,顾名思义,单向有一个next指针,双向则有另一个指针pri来指向当前节点的前驱节点,所以在双向链表中,删除操作不需要查找前驱节点,直接通过pri指针就可以找到前驱节点
结构体如下:

typedef struct TNode
{
	int data;
	struct TNode *next;
	struct TNode *pri;
}TNode,* TSList;

这里附上删除操作,不需要查找前驱节点

bool Delete_val(TSList pl,int val)//删除第一个Val值
{
	assert(pl != NULL);
	TNode *p = Search(pl,val);
	if(p == NULL)
	{
		return false;
	}
	TNode *q = p->next;
	p->pri->next = q;
	q->pri = p->pri;
	free( p);
	return true;
}

插入操作的话,和单链表要注意的点是一样的,就是多了一步,需要把新节点的pri指针保存成它的前驱,这里因为的总结的过程中全是用到头插,所以前驱为头节点,原本头节点的下一个节点的前驱改成新节点,这里要注意,当插入第一个节点时,头节点的下一个节点是NULL指针,他没有内容,所以访问后一个节点的前驱时,要进行判断具体实现如下

bool Insert(TSList pl,int val)//插
{
	assert(pl != NULL);
	TNode *p = (TNode *)malloc(sizeof(TNode));
	p->data = val;
	p->next = pl->next;
	if(p->next != NULL)
	{
		p->next->pri = p;
	}
	pl->next = p;
	p->pri = pl;
	return true;
}

内容有点多,下一次写静态链表以及变长静态链表(变形)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值