带头结点单链表操作及实现
前言
本博客为考研408数据结构单链表课程笔记,使用课本为王道408数据结构。其为随堂笔记,方便自己复习使用,若有同道中人查看,欢迎留言吐槽。
工程使用vs2019创建
一、带头结点单链表
1.单链表定义
单链表是一种链式存取的 数据结构 ,用一组地址任意的 存储单元 存放线性表中的数据元素。 链表中的数据是以结点来表示的,每个结点的构成:元素 ( 数据元素 的映象) + 指针 (指示后继元素 存储 位置),元素就是存储数据的存储单元,指针就是连接每个结点的 地址 数据。
二、单链表特征
1.使用指针来指向下一个数据元素。
2.单链表分为带头结点的单链表、不带头结点的单链表。
3.使用带头结点的单链表不需要对空表进行特殊处理,简化操作。
优缺点和适用场景:
适用于进行大量插入、删除操作的场景,不具备随机存取的特性,访问数据必须循环遍历。
三、单链表基本操作(带头结点)
1.初始化单链表
bool InitList(LinkList& L) {
L = (LNode*)malloc(sizeof(LNode));//创建头节点
if (!L)return false;
L->next = NULL;
return true;
}
2.求链表表长
int ListLength(LinkList& L) {
int len = 0;
LNode* p = L;
while (p->next) {
p = p->next;
len++;
}
printf("链表长=%d\n", len);
return len;
}
3.采用头插法建立单链表(带头结点)
//采用头插法建立单链表(带头结点)
LinkList List_HeadInsert(LinkList& L) {
LNode* s;
int x;
L = (LinkList)malloc(sizeof(LNode));//创建头节点
L->next = NULL;
printf("头插法输入:\n");
scanf_s("%d", &x);
while (x != 999)
{
s = (LNode*)malloc(sizeof(LNode));
s->data = x;
s->next = L->next;
L->next = s;
scanf_s("%d", &x);
}
printf("头插创建的链表是:");
return L;
}
4.采用尾插法建立单链表(带头结点)
LinkList List_TailInsert(LinkList& L) {
int x;
L = (LinkList)malloc((sizeof(LNode)));
L->next = NULL;
LNode* r= L;//定义一个尾指针r
LNode* s;
printf("尾插法输入:\n");
scanf_s("%d ", &x);
while (x != 999) {
s = (LinkList)malloc(sizeof(LNode));
s->data = x;
r->next = s;
r = s; //r指向新的尾节点
scanf_s("%d", &x);
}
r->next = NULL;//WE尾指针置为空;
printf("尾插创建的链表是:");
return L;
}
5.按位置序号查找结点值
//按位置序号查找结点值
LinkList LocateElem(LinkList& L, int i) {
if (i < 0) {
printf("按序查找失败\n");
return 0;
}
//if (i == 1)return NULL;
int j = 0;
LNode* p = L;
while (p && j < i) {
p = p->next;
j++;
}
// printf("按序查找的值:%d\n", p->data);//插入函数调用该函数,屏蔽输出
return p;
}
6.按值查找结点值
LinkList GetElem(LinkList& L, int e) {
int i = 1;
LNode* p = L->next;
while (p&&p->data!=e) {
p = p->next;
i++;
}
if (!p) {
printf("按值查找失败\n");
return p;
}
// printf("第%d个输入值是%d\n", i,e);//元素插入调用该函数,屏蔽打印查找的元素
return p;
}
7.后插操作,在节点p之后插入元素e
bool InsertNextNodeTail(LNode* p, int e) {
if (!p)return false;
LNode* s = (LNode*)malloc(sizeof(LNode));
if (!s)return false;
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
8.带头节点的插入操作,在第i个位置插入元素e
bool ListInsertTail(LinkList& L, int i, int e) {
if (i < 1)return false;
LNode* p = LocateElem(L, i);
printf("第%d位后插入元素%d后的链表是:",i,e);
return InsertNextNodeTail(p, e);
}
9.在第一个元素e的后边插入元素x
bool ListInsertE(LinkList& L, int e, int x) {
LNode* p = GetElem(L, e);
if (!p) {
printf("没有元素%d,插入失败\n", e);
return false;
}
printf("在元素%d后插入元素%d的链表是:", e, x);
return InsertNextNodeTail(p, x);
}
10.前插操作,在p节点前插入元素e
/*前插操作,在p节点前插入元素e
*算法思想:仍采用后插操作,待插入元素后,
* 将节点p与插入节点s的值互换。
* ********************************/
bool InsertNextNodeHead(LNode* p, int e) {
if (!p)return false;
LNode* s = (LNode*)malloc(sizeof(LNode));
if (!s)return false;
s->next = p->next;
p->next = s;
s->data = p->data;
p->data = e;
}
11.前插操作,在节点p之前插入节点s
bool InsertNextNodeHead(LNode* p, LNode* s) {
if (!p||!s)return false;
s->next = p->next;
p->next = s;
swap(p->data, s->data);
return true;
}
12.带头节点的前插操作,在第i个位置前插入元素e
bool ListInsertHead(LinkList& L, int i, int e) {
if (i < 1)return false;
LNode* p = LocateElem(L, i);
printf("第%d位前插入元素%d后的链表是:", i, e);
return InsertNextNodeHead(p, e);
}
12.删除节点操作
//1.删除第i个节点,temp是i节点的值
bool ListDeleteLocal(LinkList& L, int i) {
int temp;
if (i < 1||i>ListLength(L)) return false;
LNode* p = LocateElem(L, i-1);
if (!p) return false;
LNode* q = p->next;
temp = q->data;
p->next = q->next;
free(q);
printf("删除第%d个节点是%d\n", i, temp);
printf("删除后的链表为:");
return temp;
}
/*2.删除指定节点
* 算法思想:将p的后继节点赋值给p节点
* 释放p节点空间
* bug : 不能删除尾结点
* ******************/
bool DeleteNode(LinkList& L,int e) {
LNode* p = GetElem(L, e);
LNode* q = p->next;//将q指向p的后继节点
p->data = p->next->data;//把q的值赋给p
p->next = q->next;//把q的后继节点指向p
free(q);
printf("删除节点%d后的链表为:", e);
return true;
}
13.输出链表
//输出链表
bool ListPrint(LinkList& L) {
LNode* s;
s = L->next;
if (!s) {
printf("空表\n");
return false;
}
while (s) {
printf("%d ", s->data);
s = s->next;
}
printf("\n");
ListLength(L);
return true;
}
运行结果
总结
- Lnode是实体,而LiskList是这种类似int类型的指针
- 前插操作,在p节点前插入元素e。算法思想:仍采用后插操作,待插入元素后,将节点p与插入节点s的值互换。
- 前插操作,在节点p之前插入节点s。swap:c库函数,交换两个数据值,此部分可用以下代替。
int temp;
temp=p->data;
p->data=s->data;
s->data=temp;