单链表详解(学习笔记)

tips:

老师代码:

目录

tips:

一.链表的概念和定义

二.链表的建立

三.链表元素的读取

四.链表结点的删除

五.链表结点的插入


#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define Error 0
typedef int Status

链表是一种链式储存结构,在C语言中有着重要的作用。

分享给大家的同时也自我巩固。

一.链表的概念和定义

相对于线性表,链表有许多优点,例如在线性表中,删除或插入元素的操作很复杂,需要将插入或删除位置的前/后元素不停地移动,倘若涉及到频繁地插入或者删除的操作,链表的优点就凸显出来了。

链表作为一种链式存储结构,其的存储内容除了要存的数据元素信息之外,还储存着后继元素的存储地址。为了表示链表中每一个存储元素a(i)与其直接后继元素a(i+1)的关系,需要存储一个代表该后继元素信息的存储内容,即该元素的地址。

我们把存储当前元素信息的域称为数据域,把存储后继元素信息的域称为指针域。这两部分组合而成的一个存储单元称为节点(Node)。

 上图即为一个节点的图示,图示中,data是数据域,next就是指针域。顾名思义,next作为指针域,其存储的就是指针类型的数据,即是一个地址。

对于链表来说,需要有头有尾,因此我们通常定义一个头节点head(自行命名),head的数据域一般不存储信息,其指针与存储着第一个节点的地址。有了头节点,尾巴也不例外。作为链表的尾端,尾节点的指针域当然为空,一般用“NULL”表示。

上图为链表的结构图解,转载自其他博主的博客。

二.链表的建立

要完成一个链表的建立,与线性表相同,链表的存储形式也是结构体。

typedef struct LinkNode {
	char data;
	struct Node* next;
	
}LNode,*LinkList;

下面进行完整链表的建立的代码进程

创建单链表的过程就是一个动态生成链表的过程,即从头开始,依次建立结点,并插入链表。

思路如下:

1.声明结点p,以及计数所用数字i。

2.将数字赋值给p->data。

3.将p插入链表。

另外有必要说明的是,链表的创建有头插法和尾插法两种方式,下面我会分别提出。

(1)头插法

顾名思义头插法就是将新结点插入到下一结点的前方。代码如下:

void creat(Linklist head,int n)
{
	Linklist p;
	int i;
	//这里假设head已经被建立且其指针域为NULL
	for (i; i < n; i++)
	{
		p = (Linklist)malloc(sizeof(Node));//生成新结点
		scanf("%c", p->data);
		p->next = head->next;
		head->next = p;//插入到下一个头节点的后面一个结点
	}
}

(2)尾插法

与头插法相反,尾插法的插入方式是将新节点插入到目前链表末尾结点的后方。代码如下:

void creat(Linklist head,int n)
{
	Linklist p;
	int i;
	//这里假设head已经被建立且其指针域为NULL
	for (i; i < n; i++)
	{
		p = (Linklist)malloc(sizeof(Node));//生成新结点
		scanf("%c", p->data);
		head->next = p;
		head = p;//插入到尾部
	}
}

三.链表元素的读取

思路如下:

1.给出一个结点的位置

2.由于链表的链式存储结构,需要遍历链表至该位置

3.输出该位置的数据信息

代码如下:

void printList(Linklist head,int n)//n代表要读取的结点的位置
{
	Linklist t;
	t = head;//定义一个移动结点t指向head
	for (int i = 1; i <= n&&t!=NULL; i++)
	{
		t = t->next;
	}
	if (t != NULL)
	{
		printf("%c", t->data);
	}
	else {
		printf("结点不存在!");
	}
}

四.链表结点的删除

在实际应用内,有建立则必然少不了删除的操作。

与链表的读取相似,删除之前需要将链表先进行遍历。

但是值得思考的是,链表每一个结点都存储着数据域和指针域,那么如何才能完成链表的删除操作呢?

我用图解来讲述这个问题:

 一目了然,我们直接将p的指针域指向p->next->next,即可完成一半的删除操作,这时候链表依然是完整的。那我们不禁会想到,q的指针域仍然存在,其指向仍然是q->next,只是结点q已经被排除在链表之外了。这时候我们就需要用到free(q)这个操作来完成对q所占内存空间的释放了。

代码如下:

void deleteElement(Linklist head,int n)//n代表要删除的结点的位置
{
	Linklist t;
	t = head;//定义一个移动结点t指向head
	for (int i = 1; i < n&&t!=NULL; i++)
	{
		t = t->next;
	}
	if (t != NULL&&t->next!=NULL)
	{
		Linklist q = t->next;
		t = t->next->next;
		free(q);
	}
	else {
		printf("结点不存在!");
	}
}

五.链表结点的插入

与删除类似,删除的操作是使链表跳过要删除的结点,而插入是将一个新节点插入到该插入的位置

 但是在插入操作时要注意操作顺序。

即先将新节点s的指针域指向a1,再将原本a1之前的结点的指针域指向s。

void insertElement(LinkList head, char data, int n){
	LinkList p, q;

	// Step 1. Search to the position.
	p = head;
	for (int i = 0; i < n; i ++) {
		p = p->next;
		if (p == NULL) {
			printf("节点不存在", n);
			return;
		}
	} 

	q = (LinkList)malloc(sizeof(LNode));
	q->data = data;

	// Step 3. Now link.
	printf("linking\r\n");
	q->next = p->next;
	p->next = q;
}

整合后的运行结果

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值