带头结点单链表与不带头结点单链表的区别

 更新时间:2023年07月02日 11:49:55   作者:CD4356  
这篇文章主要介绍了带头结点单链表与不带头结点单链表的区别,需要的朋友可以参考下

链表作为一种基本数据结构,常用的链表分为带结点和不带头结点。从线性表的定义可以知道,线性表允许在任意位置进行插入和删除。所有的链表都有一个头指针head,带头结点的链表中head的数据项为空,而不带头的链表直接在头结点存入数据,那么当从头插入数据时,head需要时刻变化。

接下来具体分析:

1.带头结点的链表的插入,使用一个临时变量p等于插入之前的结点(不管具体插入位置),之后不论要插入的结点x是插到链表头还是插入到链表其他位置都是如下语句:

x->next=p->next;
p->next=x;

2.不带头结点的链表的插入,若要插入到链表的开头:

x->next=head;
head=x;  //这里不再是head->next=x;

若插到链表的其他位置:

p=插入之前的结点
x->next=p->next;
p->next=x;

3.带头结点的删除:

p是删除结点之前结点
x是要删除结点
p->next=x->next;
free(x);
同样不存在删除位置的差异。

4.不带头结点的删除:

删除第一个结点:head=head->next;这时需要改变链表的头结点。
删除其他结点时,head的值不会变。

综上所述,带头结点的单链表,不论删除和插入的位置如何,不需要修改head的值,不带头结点的单链表当头插和头删需要修改head的值。所以一般单链表一般带有头结点。

下面是其它的补充

下面的代码中,传递链表时,传的是头指针。如果是带头结点的链表,传递链表时,可以传头结点,具体可以看看 C语言实现-线性表的链式存储(单链表)

带头结点单链表 和 不带头结点单链表的区别:

  • 带头结点单链表,在进行插入、删除操作时,不需要改变链表头指针。

  • 不带头结点的单链表,在进行插入、删除操作时,可能会涉及到链表头指针的修改(所以链表作为参数传递时,传递的是头指针的引用,具体可看代码④中head_insert方法中的指针变量带了&取地址符,而代码⑤中的没有。因为带头结点单链表进行头插操作不需要修改头指针,而不带头结点的单链表进行头插操作时需要修改头指针)

  • 具体的代码也有些许差异,可对比 代码④ 和 代码⑤

带头结点单链表 和 不带头结点的init()初始化都修改了头指针,所以指针变量带了&取地址符

不带头结点的操作

① ② ③ ④ 四组代码本质是一样的。只是我本人对地址、指针、引用、指针变量概念不是很理解,所以才写了这四组代码进行对比,方便自己以后复习理解。读者可以跳过① ② ③,直接看④的代码即可

代码①

#include <stdio.h>
#include <malloc.h>
typedef struct LNode {
	int data;
	struct LNode *next;
};
void init(LNode **L) {
	*L = NULL;
}
void head_insert(LNode **L, int x) {
	LNode *newP = (LNode *)malloc(sizeof(LNode));
	newP->data = x;
	newP->next = *L;
	*L = newP;
}
LNode *get(LNode *L, int k) {
	if (k < 1) {
		printf("查找位置非法!");
		return NULL;
	}
	int i = 1;
	if (L != NULL && i <= k) {
		L = L->next;
		i++;
	}
	if (i == k) {
		return L;
	}
	printf("查找位置非法!");
	return NULL;
}
void print(LNode *L) {
	printf("\n");
	while (L) {
		printf("%4d ", L->data);
		L = L->next;
	}
	printf("\n");
}
int main() {
	LNode *L;
	init(&L);
	head_insert(&L, 15);
	head_insert(&L, 25);
	head_insert(&L, 35);
	print(L);
	printf("\n%4d \n", get(L, 2)->data);
	return 0;
}

代码②

#include <stdio.h>
#include <malloc.h>
typedef struct LNode {
	int data;
	struct LNode *next;
};
void init(LNode *&L) {
	L = NULL;
}
void head_insert(LNode *&L, int x) {
	LNode *newP = (LNode *)malloc(sizeof(LNode));
	newP->data = x;
	newP->next = L;
	L = newP;
}
LNode *get(LNode *L, int k) {
	if (k < 1) {
		printf("查找位置非法!");
		return NULL;
	}
	int i = 1;
	if (L != NULL && i <= k) {
		L = L->next;
		i++;
	}
	if (i == k) {
		return L;
	}
	printf("查找位置非法!");
	return NULL;
}
void print(LNode *L) {
	printf("\n");
	while (L) {
		printf("%4d ", L->data);
		L = L->next;
	}
	printf("\n");
}
int main() {
	LNode *L;
	init(L);
	head_insert(L, 15);
	head_insert(L, 25);
	head_insert(L, 35);
	print(L);
	printf("\n%4d \n", get(L, 2)->data);
	return 0;
}

代码③

#include <stdio.h>
#include <malloc.h>
typedef struct LNode {
	int data;
	struct LNode *next;
}*LinkList;
void init(LinkList *L) {
	*L = NULL;
}
void head_insert(LinkList *L, int x) {
	LinkList newP = (LinkList)malloc(sizeof(LNode));
	newP->data = x;
	newP->next = *L;
	*L = newP;
}
LinkList get(LinkList L, int k) {
	if (k < 1) {
		printf("查找位置非法!");
		return NULL;
	}
	int i = 1;
	if (L != NULL && i <= k) {
		L = L->next;
		i++;
	}
	if (i == k) {
		return L;
	}
	printf("查找位置非法!");
	return NULL;
}
void print(LinkList L) {
	printf("\n");
	while (L) {
		printf("%4d ", L->data);
		L = L->next;
	}
	printf("\n");
}
int main() {
	LinkList L;
	init(&L);
	head_insert(&L, 15);
	head_insert(&L, 25);
	head_insert(&L, 35);
	print(L);
	printf("\n%4d \n", get(L, 2)->data);
	return 0;
}

代码④

#include <stdio.h>
#include <malloc.h>
//结构体
typedef struct LNode {
	int data;
	struct LNode *next;
} *LinkList;
//初始化
void init(LinkList &L) {
	L = NULL;
}
//头插
void head_insert(LinkList &L, int x) {
	LinkList newP = (LinkList)malloc(sizeof(LNode));
	newP->data = x;
	newP->next = L;
	L = newP;
}
//按位序查找
LinkList get(LinkList L, int k) {
	if (k < 1) {
		printf("查找位置非法!");
		return NULL;
	}
	int i = 1;
	if (L != NULL && i <= k) {
		L = L->next;
		i++;
	}
	if (i == k) {
		return L;
	}
	printf("查找位置非法!");
	return NULL;
}
//遍历输出
void print(LinkList L) {
	printf("\n");
	while (L) {
		printf("%4d ", L->data);
		L = L->next;
	}
	printf("\n");
}
int main() {
	LinkList L;
	init(L);
	head_insert(L, 15);
	head_insert(L, 25);
	head_insert(L, 35);
	print(L);
	printf("\n%4d \n", get(L, 2)->data);
	return 0;
}

带头结点的操作

代码⑤

#include <stdio.h>
#include <malloc.h>
//结构体
typedef struct LNode {
	int data;
	struct LNode *next;
} *LinkList;
//初始化
void init(LinkList &L) {
	LinkList newp = (LinkList)malloc(sizeof(LNode));
	newp->next = NULL;
	L = newp;
}
//头插
void head_insert(LinkList L, int x) {
	LinkList newp = (LinkList)malloc(sizeof(LNode));
	newp->data = x;
	newp->next = L->next;
	L->next = newp;
}
//按位序查找
LinkList get(LinkList L, int k) {
	if (k < 1) {
		printf("查找位置非法!");
		return NULL;
	}
	int i = 1;
	LinkList p = L->next;
	if (p != NULL && i <= k) {
		p = p->next;
		i++;
	}
	if (i == k) {
		return p;
	}
	printf("查找位置非法!");
	return NULL;
}
//遍历输出
void print(LinkList L) {
	printf("\n");
	LinkList p = L->next;
	while (p) {
		printf("%4d ", p->data);
		p = p->next;
	}
	printf("\n");
}
int main() {
	LinkList L;
	init(L);
	head_insert(L, 15);
	head_insert(L, 25);
	head_insert(L, 35);
	print(L);
	printf("\n%4d \n", get(L, 2)->data);
	return 0;
}

到此这篇关于带头结点单链表与不带头结点单链表的区别的文章就介绍到这了,更多相关带头与不带头结点单链表区别内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java string对象上的操作,常见的用法你知道吗

    java string对象上的操作,常见的用法你知道吗

    今天给大家带来的是关于Java的相关知识,文章围绕着Java String类用法展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-08-08
  • 利用C++模拟实现STL容器:list

    利用C++模拟实现STL容器:list

    列表是一种顺序容器,它允许在序列中的任何位置执行常量时间插入和删除操作,并允许在两个方向上进行迭代。本文将利用C++模拟实现list,希望对大家有所帮助
    2022-12-12
  • c++ 标准库多线程问题小结

    c++ 标准库多线程问题小结

    C++11 引入了<thread>库,使得多线程编程更加方便,以下是一些基本概念和示例,帮助你理解如何在 C++ 中进行多线程编程,这篇文章主要介绍了c++ 标准库多线程,需要的朋友可以参考下
    2025-03-03
  • C语言使用ffmpeg实现单线程异步的视频播放器

    C语言使用ffmpeg实现单线程异步的视频播放器

    这篇文章主要为大家详细介绍了C语言如何使用ffmpeg实现单线程异步的视频播放器功能,文中的示例代码讲解详细,感兴趣的小伙伴可以尝试一下
    2022-12-12
  • 对C语言中递归算法的深入解析

    对C语言中递归算法的深入解析

    C通过运行时堆栈支持递归函数的实现。递归函数就是直接或间接调用自身的函数
    2013-07-07
  • 使用Qt实现旋转动画效果

    使用Qt实现旋转动画效果

    这篇文章主要为大家详细介绍了如何使用Qt实现旋转动画效果,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-11-11
  • C++实现LeetCode(100.判断相同树)

    C++实现LeetCode(100.判断相同树)

    这篇文章主要介绍了C++实现LeetCode(100.判断相同树),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • 应用程序操作NorFlash示例代码分享(norflash接口使用方法)

    应用程序操作NorFlash示例代码分享(norflash接口使用方法)

    相对于操作NandFlash,操作NorFlash相对简单,因为基本不需要考虑坏块,NorFlash也没有OOB区域,也跟ECC没有关系。读写擦除相对容易,下面看个例子吧
    2013-12-12
  • C++归并法+快速排序实现链表排序的方法

    C++归并法+快速排序实现链表排序的方法

    这篇文章主要介绍了C++归并法+快速排序实现链表排序的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • VS2010+Opencv+MFC读取图像和视频显示在Picture控件

    VS2010+Opencv+MFC读取图像和视频显示在Picture控件

    这篇文章主要为大家详细介绍了VS2010+Opencv+MFC读取图像和视频显示在Picture控件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-08-08

最新评论