数据结构学习笔记——单链表

准备知识在另一篇博客:单链表预备知识

建立单链表:
头插法:

每次都是从头结点插入一个元素的方法,所以它是倒序的。
在这里插入图片描述

typedef struct LNode //创建结点结构体,由数据域和指针域组成
{
	Elemtype data;
	struct LNode *next;
} LinkNode;

void CreateListF (LinkNode *&L,Elemtype a[], int n)
{
	LinkNode *s;
	L = (LinkNode *)malloc(sizeof(LinkNode)); 
	L ->next = NULL; //创建一个头结点L
	
	for (int i = 0; i < n; i ++)
	{
		s = (LinkNode *)malloc(sizeof(LinkNode));
		s -> data = a[i];

		s ->next = L ->next;
		L ->next = s;
	}//从数组a中读取数据,并把结点插入链表。
}

尾插法:
每次插入是在当时的尾结点,所以结点的顺序是正常的。为了能够在末尾插入,我们应该需要一个指针r始终指向链表的结尾(即每次插入一个新结点后都要把r指向这个新结点),以方便插入数据,最后还要把r指向的尾结点的指针域设置为NULL。
在这里插入图片描述

void CreateListR(LinkNode * &L,Elemtype a[], int n)
{
	//初始化表
	LinkNode *r,*s;
	L = (LinkNode *)malloc(sizeof(LinkNode)); 
	r = L;
	for (int i = 0; i < n; i ++)
	{
		LinkNode *s = (LinkNode *)malloc(sizeof(LinkNode));
		s -> data = a[i];
		r -> next = s;
		r = s;
	}//读取元素值,插入结点。
	r -> next = NULL; 
}

单链表中的线性表基本运算:
初始化单链表:

void InitList(LinkNode *&L)
{
	L = (LinkNode *)malloc(sizeof(LinkNode));
	L -> next = NULL;
}//创建头结点,即为初始化单链表 

在这里插入图片描述
销毁单链表:
所谓销毁单链表其实就是释放每个结点的空间,这里需要两个指针pre和p,分别指向头结点和首结点,循环操作就是:释放pre所指向的结点,pre跑到p这里来,p跑到下一个结点。算法会用到while循环,循环的条件是p != NULL,理解方法如下:释放了倒数第二个结点后,pre跑到最后一个结点这里,p跑到NULL那里去了,这时候pre在最后一个结点,还没有释放,所以循环结束后单独写一个语句释放最后一个结点。
在这里插入图片描述

void DestroyList(LinkNode *&L)
{
	LinkNode *pre,p;
	pre = L;
	p = L -> next;
	
	while (p != NULL)
	{
		free(pre);
		pre = p;
		p = pre -> next;
	}
	free(pre);

判断线性表是否为空表:
判断是否为空表其实只需要判断头结点的指针域是否为空即可,为NULL就说明头结点后面没有结点,也就是没有元素了。

 bool ListEmpty(LinkNode *L)
 {
 	return (L -> next == NULL);
  } //判断是否为空表 

求线性表的长度:
这里的长度是指元素个数,并没有包括头结点。由于单链表中没有顺序表中的length域,所以只能够通过遍历+记数的方式来得到长度。

int LengthList(LinkNode *L)
{
	int n = 0;
	LinkNode *p = L;
	while (p -> next != NULL)
	{
		p = p -> next;
		n ++;
	}
	return n;
	//return length;
 } //计算单链表的长度
 //千万注意!!如果对链表插入或修改了元素,那么length将不会是链表的长度,
 //除非在修改的时候也对array[length]做修改 

其实单链表的长度就是data域的个数,也就是array的元素个数,所以这个函数可以直接返回length。
输出线性表:
输出方法就是遍历每一个结点,然后输出数据域,当指针为NULL并输出之后,结束循环。

void DisplayList(LinkNode *L)
{
	LinkNode *p = L -> next; //p指向首结点
	while (p != NULL)
	{
		printf("%d", p -> data);
		p = p -> next;
	}//对于每一个结点,都会进行判断,输出,移动,那么最后一个结点也会判断,输出,移动,
	//移动后,需要结束循环,这时p为NULL,那么条件可以为 p != NULL

求线性表中某个数据元素的值:

bool GetElem(LinkNode *L, int i, Elemtype &e)
 {
 	int j = 0;
 	LinkNode *p = L;
 	while (j != i && p != NULL)
 	{
 		j ++;
 		p = p -> next;
	 }//当j还没到i那里并且p所指向的元素不是最后一个结点的指针域所指向的空间(NULL)时,
	 //循环继续。
	 
	if (p == NULL) return false;
	else
	{
		e = p -> data;
		return true;
	 } //到了最后,i错误,返回false或者是到了i那里,输出这个结点的data域。
  } 

插入数据元素:
注意,这里的插入数码元素是指在已经占用的逻辑序号上插入,在最后一个元素的后一个位置插入是不可以的,插入到最后的后一个位置可以用尾插法。

bool Listinsert(LinkNode *&L, int i, Elemtype e)
{
	int j = 0;
	LinkNode *p = L,*s;
	if (i <= 0) return false; 
	while (j < i - 1 && p != NULL)
	{
		j ++;
		p = p -> next;
	}//找第i-1个结点,i没问题则j = i-1,p指向i-1个结点,否则p = NULL,j没有意义
	
	if (j == i - 1)
	{
		s = (LinkNode *)malloc(sizeof(LinkNode));
		s -> next = NULL;
		s -> data = e;//创建一个data域为e的结点,由s指向。 
		
		s -> next = p -> next;
		p -> next = s; //s所指向的结点占用第i个位置,插入到单链表中
		
		return true; 
	}
	if (p == NULL) return false; 
 } 

在任意位置插入都能够给出满意的答复的插入算法:

bool InsertElement(LinkNode *&L, int i, Elemtype e)
{
	int Length; 
	Length = LengthList(L);//线性表的最新长度 
	int j = 0; LinkNode *p = L,*s = (LinkNode *)malloc(sizeof(LinkNode));s -> data = e;s ->  next = NULL;
	//j 为计数器,j=0表示在头结点,p为指向链表结点的指针,刚开始是
	//指向头结点,初始化s,并把data域改为想要插入的值,指针域改为NULL。 
	if (i < 0)
	{
		printf("参数i不能为负数!\n");
		return false; 
	}
	else if (i == 0)//在首结点前面的第一个位置插入,头插法。 
	{
		s -> next = p -> next;
		p -> next = s;
		printf("在最前面插入新元素成功!此时a1 = %d\n", s -> data);
		return true; 
	 } 
	else if (0 < i <= Length)//插入位置是某个元素的位置 
	{
		int j = 0;
		while (j != i-1) //使p指向第i-1个结点 
		{
			j ++;
			p = p -> next; 
		}
		s -> next = p -> next;
		p -> next = s;
		printf("在第%d个位置插入成功!此时a%d = %d\n", i,i,s -> data);
		return true;
	}
	
	else if (i == Length + 1)
	{
		
		while (j != Length)//p指向最后一个结点 
		{
			j ++;
			p = p -> next;
		}
		p -> next = s;
		printf("在最后面插入新元素成功,此时a%d = %d\n", i,s -> data);
		return true;
	}
	else 
	{
		printf("i参数过大!\n"); 
		return false;//i 已经大于length + 1了,i参数错误 
	}
}

删除数据元素:

做法就是:若i合法,则找到第i-1个结点,然后进行删除操作。

bool ListDelete(LinkNode *&L, int i, Elemtype &e)
{
	if (i <= 0)	{printf("参数i不能够为负数!"); return false;}
	else if (i > LengthList(L)) {printf("参数i过大!"); return false; }
	//排除掉i的非法性 
	else
	{
		int j = 1; LinkNode *p = L -> next;
		while (j < i-1)
		{
			j ++;
			p = p -> next;
		}//使p指向第i-1个结点。
		
		LinkNode *agent = p -> next;//标记被删除元素。
		e = agent -> data;
		p -> next = agent -> next;
		free(agent); 
		return true;
	}
 } 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值