数据结构-讲解单链表

为了完成学校假期作业被迫营业,想要整个完整的代码可以评论我私发给你,哈哈哈,仅供参考不喜勿喷,欢迎大佬指点

大家好我今天为大家讲的是链表。
想必大家一定会问:

什么是链表?

链表是一中物理存储单元上非连续,非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针连接次序实现的。

这句话可能会不好理解 ,没关系我会带领大家进一步理解

那么,我来问问大家

链表由什么组成的呢?

链表是由一系列结点组成的,而每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

如图所示

在这里插入图片描述

代码如下:

typedef int ElementType;
struct Node
{
	ElementType date;
	struct Node* next;
};
typedef struct Node* List;//链表
typedef List Position;//位置

结点有了 那我们如何创建链表呢 ?

观察上面的图我们会发现链表都是有一个结点作为头结点,后面的每个结点都是通过上一个指针域找到的,所以我们创造链表首先要为链表创造出一个头结点。

struct Node* L=NULL;
L = makelist(L);

头结点创建完后,我们知道头结点是struct LNode*类型的指针,所以我们为头结点分配内存空间,

struct Node* makelist(struct Node* L)
{
	L = (struct Node*)malloc(sizeof(struct Node));
	L->next = NULL;
	return L;
}

拥有了头结点,那么链表就可以进行插入数据了

如何向链表中插入数据呢?

插入的方法有两种一个是头插法,而另一个是尾插法

那么我先说头插法,头插法就是将新结点插入到当前链表的头结点之后

在这里插入图片描述

答案:不可以颠倒顺序的;

L->next中存储的是A结点的地址 如果 没有把A结点的地址保存 而直接把B结点的地址装进L->next,那么A结点的地址将会丢失,我们就无法再访问A结点(若A结点后面还有结点我们也将无法访问)

代码实现:

//插入元素(头插法)
void Insert(ElementType X, List L)
{
	Position TmpCell, age;
	TmpCell = malloc(sizeof(struct Node));
	if (TmpCell == NULL)
		printf("内存申请失败");
	//将数据放入插入结点的数据域内
	TmpCell->date = X;
	//将新节点插入链表中
	TmpCell->next = L->next; 
	L->next = TmpCell;
	printf("插入成功\n");
}

而尾插法就是将新结点插入到当前链表的尾结点之后

在这里插入图片描述

答案:不可以颠倒顺序的;

因为r指向的是链表末尾的结点,如果我们先把r指向新生成的结点s,这样我们就无法找到链表末尾结点,那么我们还怎么把新生成的结点插入链表的末尾呀!所以顺序不可以颠倒的。

尾插法的代码,由于时间关系我没有写,但有兴趣的可以自己去了解的一下原理和我讲的没什么差别,也很容易就可以实现。

有些同学说插入了这么多结点我都不知道插入多少个结点啦,

所以我们可以创造出一个函数 打印链表中的每个结点,这样我们就可以清楚链表中有那些结点啦,一目了然。

如何打印链表?

代码实现:

//打印链表
void Printf(List L)
{
	Position P,Tmp;
	P = L->next;
	while (P != NULL)
	{
		Tmp = P->next;
		printf("%d->", P->date);
		P = Tmp;
	}
	printf("NULL\n");
}

当然,有了插入结点就有他的对立删除结点

如何删除链表中的结点呢?

我们可以通过结点中数据域中的数据寻找我们所要删除的结点,通过数据遍历整个链表找到我们要删除的结点的前一个结点。注意这里要找的是删除的结点的前一个结点。如果链表中每个结点存放的数据都不是我们所要删除的数据,那么我们就不进行结点删除。

清楚思路之后来看看如何用代码实现呢?

代码如下:

//检测链表是否为末尾
int IsLast(Position P, List L)
{
	return P->next == NULL;
}
//返回要删除元素结点的前一个结点的位置
Position FindPrevious(ElementType X, List L)
{
	Position P;
	P = L;
	while (P->next != NULL && P->next->date!= X)
		P = P->next;
	return P;
}
//删除链表上的某一个结点
void Delete(ElementType X, List L)
{
	Position P, TmpCell;
	P = FindPrevious(X, L);
	if (!IsLast(P, L))
	{
		TmpCell = P->next;
		P->next = TmpCell->next;
		free(TmpCell);
	}
}

那么有的同学说一个一个删除结点,好费劲 有没有快捷的方法能够把整个链表中的结点全部删除呢,我可以负责人的告诉你当然有啦

如何将链表清空?

我们直接看代码还是很简单的

//清空链表
void DeleteList(List L)
{
	Position P, Tmp;
	P = L->next;
	L->next = NULL;
	while (P != NULL)
	{
		Tmp = P->next;
		free(P);
		P = Tmp;
	}
}

我们还可以检测链表是否清空成功

//检验链表是否为空
int IsEmpty(List L)
{
	return L->next == NULL;
}
int main()
{
    ......
    if (IsEmpty(L))
	{
		printf("链表为空\n");
	}
	else
	{
		printf("链表不为空\n");
	}
    ......
}

这样整个链表的知识我们就学完了

我们来一起回顾一下我们都学了那些知识

1.什么是链表

2.链表的组成

3.链表的创建

4.向链表中插入结点

5.从链表中删除结点

6.链表的打印

7.链表的清空

记得掌握这七个小知识点哦,谢谢大家

猜你喜欢

转载自blog.csdn.net/damowangsx/article/details/107859703