本文章基于个人最近对数据结构单链表部分的学习所整理,具有一定的练习性质,可能含有一些初学者犯的错误,如果有一些错误,希望可以得到前辈们的指正与批评,在此先谢谢大家。
本文介绍单链表的初始化、插入操作(指定位置前插和后插)、删除指定位置、查找位置(按位置查找、按值查找)几个部分的基本内容。
目录
前言
链式存储线性表,简称链表,包括:单链表,双链表,循环链表和静态链表;
顺序存储线性表,简称顺序表;
区别:链式存储线性表不需要使用连续的存储单元,不要求逻辑上相邻的两个元素在物理位置(内存上的位置)相邻,它通过指针建立起数据元素之间的关系。
一、结点是什么?
线性表的链式存储又称单链表,为了建立数据元素之间的线性关系,对每个链表的结点,除了存放自身元素(data)以外,还需要存放一个后续指针(next),其中data为数据域,next为(存放后续结点),可以通过一下代码来表示一个struct LNode类型的结点的内容:
typedef struct LNode
{
int data;
struct LNode* next;
}LNode,*LinkList;
//线性表中单个结点的描述
//struct LNode = LNode
//struct LNode*=LinkList(头结点)
二、基本操作
1.线性表初始化
代码如下(示例):
int main()
{
LinkList L;
L = (LinkList)malloc(sizeof(LinkList)); //头结点开辟内存空间
if (L != NULL)
{
L->next = NULL; //L指向头结点,头结点的next指向NULL
printf("初始化成功!\n");
}
else
printf("初始化失败!\n"); //L指向NULL,创建失败
//单链表的初始化操作
...
}
2.插入操作
2.1头插法:
LinkList List_HeadInsert(LinkList L)//头插法
{
LNode* s;
int x;
L = (LinkList)malloc(sizeof(LinkList)); //头结点开辟内存空间
L->next = NULL; //先建立 L -> 头结点 -> NULL
scanf("%d", &x);
while (x!=9999) //输入9999则停止新建结点
{
s =(LNode*) malloc(sizeof(LNode));
s->data = x;
s->next = L->next;
L->next = s;
scanf("%d", &x);
while (getchar() != '\n') //处理多余输入,处理缓冲区多余输入(scanf只接受数字)
continue;
}
return L;
}//头插法
可以理解为插入都是在头结点之后插入的。
2.1尾插法
LinkList List_NextInsert(LinkList L)//尾插法
{
int x;
LNode* s;
LNode* r; //末尾节点r
r = L; //r先指向头节点L
scanf("%d", &x);
while (x != 9999)
{
s = (LNode*)malloc(sizeof(LNode));
s->data = x;
r->next = s;
r = s;
scanf("%d", &x);
while (getchar() != '\n')
continue;
}
r->next = NULL;
return L;
}
头插法一开始就要注意先让L->next=NULL,而尾插法注意最后让指向最后一个结点的r,使得r->next=NULL,两者时间复杂度相等,插入一个结点的时间为O(1),插入n个则为O(n)。
2.3指定结点插入(第i个位置插入元素e)
一般的单链表结点插入的思路和头插法、尾插法大致相同:思路为先遍历单链表找到你要插入的位置,然后选择往前插入或者往后插入:
bool InsertList(LinkList L, int i,int e)
{
if (i < 1)
return false;
int j=0;
LNode* p;
p = L;
while (p!=NULL && j < i-1) //遍历单链表直到找到第i-1个结点
{
p = p->next;
j++;
}
if (p == NULL)
{
return false;//找到最后的结点都没有找到
}
LNode* s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
头结点不算位置,记作i=0,第0个位置,因为头结点不存储元素数据,只有指针。
3.删除操作
删除单链表第i个位置(头结点为第0个位置),与之前相同我们首先要遍历找到第i-1个结点,如删除第1个结点,则要找到第0个结点位置,也就是头结点的位置,如删除第5个结点,则要找到第4个结点的位置,是一个普通结点。
LNode* q=p->next; //q指向要删除的结点
e=q->data;
p->next=q->next //p指向q之后的结点 *q从单链表断开
free(q); //释放q的空间
指定删除位置
bool DeleteNode(LNode* p)
{
LNode*q=p->next;
p->data=q->data;
free(q);
return true;
}
4.查找操作
其实前面所提及的遍历单链表就是查找操作的基础,这里就简要描述按位置查找和按值查找两种。
//按位置查找
LNode* p;
p = L;
while (p!=NULL && j < i-1) //遍历单链表直到找到第i-1个结点
{
p = p->next;
j++;
}
//按值查找
LNode* p;
P = L;
int e = value;
while (p!=NULL && p->data!=value)
{
p = p->next;
j++;
}
三、总结与个人介绍
单链表是数据结构中的基本思想,是最基本的结构类型,随着学习的深入,越来越多的对结构操作会导致代码的冗杂,因此要开始有封装函数和思想,提高代码的可读性。
这是我个人的第一条博客,对于单链表一些操作只给了部分相关代码和导图,没有完整的代码,存在很大程度上的欠缺,未来会根据学习进一步修正。
本人本硕都为211工科非科班,可以说和编程没有什么交集,只有大一大二学的C语言和地理信息系统课程涉及到部分编程,与其他科班同学相比少了将近五年的基础,所以我对学习的目标就是培养最基本的编程的思想,尽量弥补前面基础知识的空缺,对于如何学习编程,还是得从自己的能力和想法出发,学习编程是个很漫长的过程,C、C++、数据结构、面向对象程序设计、操作系统、计算机网络、计算机组成原理、数据库原理、编译原理等专业基础知识等着我们去学习,所以重中之重还是自己的学习安排和期望。