数据结构--单链表(带头结点)(王道408数据结构)

2 篇文章 0 订阅
2 篇文章 0 订阅


前言

本博客为考研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;
  • 删除指定节点
    *算法思想:将p的后继节点赋值给p节点,释放p节点空间
    *bug : 不能删除尾结点(没有解决)
  • 参考资料:百度百科
    王道数据结构
    知乎
    完整工程下载
  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值