数据结构(二)——单链表的头插与尾插

一、引言

上篇文章我们知道了顺序表的缺点:

  • 插入和删除操作需要移动大量元素。
  • 数组的大小不好确定。
  • 存储分配需要一整段连续的存储空间,不够灵活,造成很多碎片(空闲的空间得不到利用)。

所以我们就引入了单链表

二、简述单链表

单链表中逻辑上相邻的两个元素在物理位置上不相邻,一个结点分为数据域和指针域,如下图,1的指针域(指针变量)存放2的起始地址,以此类推,就很像我们生活中的火车,最后一个结点的指针域为NULL,当我们在遍历的时候遇到NULL,就明白是单链表的结束

括号外面的LNode是别名等价于struct LNode,LinkList等价于struct LNode *LinkList

 三、单链表的实现

头指针:链表中第一个结点的存储位置,用来标识单链表

头结点:在单链表的第一个结点(a1)之前附加的一个结点,为了操作的方便(带头结点就是头结点没数据)

        若链表有头结点,则头指针永远指向头结点,不论链表是否为空,头指针均不为空,头指针是链表的必要元素,标识一个链表。
        头结点为了操作的方便,其数据域一般为空,或者存放链表的长度。有头结点后,对在第一结点前插入和删除第一结点的操作就统一了 ,不用频繁重置头指针。但头结点不是一定要的。

 头插、尾插、中间插如下图

 

(a)(b)插入的代码:

 这里的p即为代码中的L(链头)

 (c)插入的代码:

四、代码

#include <stdlib.h>
#include <stdio.h>
#include <iostream.h>

typedef int ElemType;//单链表中的元素类型
//单链表结点的定义
typedef struct LNode{//单链表结点类型
	ElemType data;//数据域
	struct LNode *next;//指针域 指向下一个结点
}LNode,*LinkList;//*LinkList等价于struct LNode *LinkList
/*头插法建立单链表*/
LinkList createListH(LinkList &L)
{
	LNode *q;
	int n;
	L=(LinkList)malloc(sizeof(LNode));//带头结点的链表
	L->next=NULL;//L.data没存数据
	scanf("%d",&n);//读取数据
	while (n!=999)
	{
		q=(LNode*)malloc(sizeof(LNode));//申请新空间给q
		q->data=n;//把读取的值给q->data
		q->next=L->next;//新结点的next指针指向链表的第一个元素(第一个放数据的元素)
		L->next=q;
		scanf("%d",&n);//继续读取

	}
	
	return L;
}
/*尾插法建立单链表*/
LinkList createListT(LinkList &L)
{
	L=(LinkList)malloc(sizeof(LNode));//带头结点的链表
	LNode *q,*r=L;//写成LinkList q,r=L;也可以,这里r一开始就是表尾结点指向链表尾部
	int n;
	scanf("%d",&n);//读取数据
	while (n!=999)
	{
		q=(LNode*)malloc(sizeof(LNode));//申请新空间给q
		q->data=n;//把读取的值给q->data
		r->next=q;//尾部结点指向新结点
		r=q;//r指向新的表尾结点
		scanf("%d",&n);//继续读取

	}
	r->next=NULL;//尾指针的next指针赋值为空
	return L;
	
}
void printList(LinkList L)//这里L没用引用,不会改变主函数里面的L
{
	L=L->next;
	while (L!=NULL)
	{
		printf("%3d",L->data);
		L=L->next;//打印完数据指向下一个结点继续打印,直到L=NULL
	}
	printf("\n");
}
int main()
{
	LinkList L;//链头 结构体指针类型
	LinkList pfind;//存储拿到的某个结点

	createListH(L);//输入 1 2 3 4 5
	//createListT(L);
	printf("头插法打印链表元素如下:\n");
	printList(L);//打印链表

	return 0;
}

1、scanf("%d",&n);输入时会忽略空格 ,可以一次性输一排,空格隔开 

2、 注意尾插法中一定要把尾指针的next指针赋值为空(r->next=NULL;),不然会出现异常,不是NULL,就会指向申请的空间的地址,在打印链表时进入while循环判断时不等于NULL,就会去拿它指向的空间的数据(L->data),而这个地址是不可读的,这时候去访问就出现异常

五、结果

输入1 2 3 4 5 999(遇到999回车结束输入)

 遇到的bug:尾插法输入完直接结束,如图

调试如下:

发现问题:

解决问题:链头要先申请空间再赋值给结点r

 原创不易,转载请注明出处:

数据结构(二)——单链表的头插与尾插

猜你喜欢

转载自blog.csdn.net/hml111666/article/details/122858833