单链表,头插法,尾插法各种函数详解

版权声明:谢谢 https://blog.csdn.net/Waybyway/article/details/83449668

一:LinkList.cpp文件

#include <stdio.h>
#include <malloc.h>         //malloc函数 用了<stdlib.h>中的 <malloc.h>头文件
typedef int ElemType;       //自定义类型 使 ElemType 为 int型
typedef struct LNode  		//定义单链表结点类型
{
	ElemType data;
	struct LNode *next;		//定义链表结点类型的指针 指向后继结点
} LinkList;
/*  链表中 不同对指针变量的不同引用的解释
    在main()函数里 创建的是 LinkList *L;
    LinkLIst类型的指针变量 *L,变量L本身有地址,
    作为指针变量也会存储 指向元素的地址
    如 L=(LinkList *)malloc(sizeof(LinkList));  	//创建头结点
    L指向了 通过malloc 函数从内存里动态获取的一块区域的 地址
    在主函数读取CreateListR(L,a,n);之前L没有储存地址不能用 *L
    我的另外一篇转载博客  https://blog.csdn.net/Waybyway/article/details/83385551
    在C语言里没有C++所谓的“按引用传递”,解释了C 和C++ 的不同

    链表所有改变链表函数长度的函数如
    一: 头插法,尾插法创建,初始化,销毁,插入,删除元素等函数用的参数是(LinkList *&L)
    *&L表示 *是间接运算符 对&L(L本身的地址)间接运算,

    二:其他函数参数都是(LinkList *L)


*/
/*单链表 头插法解释
    在主函数main()中 的指针Linklist *L用来创建链表;
    L为头结点,首地址存在这个里面了
    L=(LinkList *)malloc(sizeof(LinkList));  	//创建头结点
    在输入之前现将他的指向置为 空NULL
    通过malloc(sizeof(LinkList))动态分配sizeof(LinkList)的大小的空间
    malloc函数的默认返还类型使 void类型,转换成 (LinkList *)类型
    这样就创建了一个新结点 S
    s->data=a[i]; s结点的data值被赋值为 a[i];

    由于头结点 L->next=NULL,所以 s->next=L->next;
    s->next 的指向也是NULL

    L->next=S; 头结点 L指向了 第一个S (这个S记作 S_0)
    这样头结点L就在 所有新结点的前面,最后使S_0结尾 指向为空
    for(), 产生下一个 S_1
    同样 S_1 的data被赋值,s->next=L->next;
    上一步 L指向 S_0即上一个 S,这样S_1也指向了S_0
    L->next=s;  L这样就指向了 S_1
    总之 S_0指向空,新的 S结点指向前一个 S结点
    头结点L就在 所有新结点的前面,最后使S_0结尾 指向为空
    最后生成的链表就是这样 链表 数值序列是 数组序列的逆序
    L -> S_(N-1) -> S_(N-2) -> S_(N-3)……………… -> S_(1) -> S_(0) -> NULL
*/
void CreateListF(LinkList *&L,ElemType a[],int n)
//头插法建立单链表,将长度为N的数组 a[]创建为链表
{
	LinkList *s;int i;
	L=(LinkList *)malloc(sizeof(LinkList));  	//创建头结点
	L->next=NULL;
	for (i=0;i<n;i++)
	{
		s=(LinkList *)malloc(sizeof(LinkList));//创建新结点
		s->data=a[i];
		s->next=L->next;			//将*s插在原开始结点之前,头结点之后
		L->next=s;
	}
}
/*尾插法,部分解释与头插法不再叙述
    L为头结点 ,指向为空
    r=L; R 的指向也为空,R 的位置与L并列
    产生新结点 S ,data被赋值为a[i]
    r->next=s;			//将*s插入*r之后
    R 的位置与L并列
    头结点L 指向 新产生的S结点 记作S_0
    r=s;  R 的位置与S_0并列
    S_1产生 ,S_1的data被赋值
    因为原来R与S_0并列,所以 r->next=s;
    这样S_0就指向了S_1
    最后一个S_(n-1)产生,R与他并列
    最后指向空NULL
    总之 R指针每次与新产生结点并列,让新结点指向下一个新结点
    到最后一个结点 指向空
    所以尾插法建立的链表 数值序列是 数组序列
    L -> S_(0) -> S_(1) -> S_(2)………………  -> S_(N-2)-> S_(N-1) -> NULL
*/
void CreateListR(LinkList *&L,ElemType a[],int n)
//尾插法建立单链表
{
	LinkList *s,*r;int i;
	L=(LinkList *)malloc(sizeof(LinkList));  	//创建头结点
	L->next=NULL;
	r=L;					//r始终指向终端结点,开始时指向头结点
	for (i=0;i<n;i++)
	{
		s=(LinkList *)malloc(sizeof(LinkList));//创建新结点
		s->data=a[i];
		r->next=s;			//将*s插入*r之后
		r=s;
	}
	r->next=NULL;			//终端结点next域置为NULL
}
void InitList(LinkList *&L)
{
	L=(LinkList *)malloc(sizeof(LinkList));  	//创建头结点
	L->next=NULL;
}
void DestroyList(LinkList *&L)
{
	LinkList *p=L,*q=p->next;
	while (q!=NULL)
	{	free(p);
		p=q;
		q=p->next;
	}
	free(p);	//此时q为NULL,p指向尾结点,释放它
}
bool ListEmpty(LinkList *L)
{
	return(L->next==NULL);
}
int ListLength(LinkList *L)
{
	LinkList *p=L;int i=0;
	while (p->next!=NULL)
	{	i++;
		p=p->next;
	}
	return(i);
}
void DispList(LinkList *L)
{
	LinkList *p=L->next;
	while (p!=NULL)
	{	printf("%d ",p->data);
		p=p->next;
	}
	printf("\n");
}
bool GetElem(LinkList *L,int i,ElemType &e)
{
	int j=0;
	LinkList *p=L;
	while (j<i && p!=NULL)
	{	j++;
		p=p->next;
	}
	if (p==NULL)			//不存在第i个数据结点
		return false;
	else					//存在第i个数据结点
	{	e=p->data;
		return true;
	}
}
int LocateElem(LinkList *L,ElemType e)
{
	LinkList *p=L->next;
	int n=1;
	while (p!=NULL && p->data!=e)
	{	p=p->next;
		n++;
	}
	if (p==NULL)
		return(0);
	else
		return(n);
}
bool ListInsert(LinkList *&L,int i,ElemType e)
{
	int j=0;
	LinkList *p=L,*s;
	while (j<i-1 && p!=NULL) //查找第i-1个结点
	{	j++;
		p=p->next;
	}
	if (p==NULL)	//未找到位序为i-1的结点
		return false;
	else			//找到位序为i-1的结点*p
	{	s=(LinkList *)malloc(sizeof(LinkList));//创建新结点*s
		s->data=e;
		s->next=p->next;						//将*s插入到*p之后
		p->next=s;
		return true;
	}
}
bool ListDelete(LinkList *&L,int i,ElemType &e)
{
	int j=0;
	LinkList *p=L,*q;
	while (j<i-1 && p!=NULL)	//查找第i-1个结点
	{	j++;
		p=p->next;
	}
	if (p==NULL)				//未找到位序为i-1的结点
		return false;
	else						//找到位序为i-1的结点*p
	{	q=p->next;				//q指向要删除的结点
		if (q==NULL)
			return false;			//若不存在第i个结点,返回false
		e=q->data;
		p->next=q->next;		//从单链表中删除*q结点
		free(q);				//释放*q结点
		return true;
	}
}

二:含有主函数的Exam2-6.cpp文件

#include "linklist.cpp"
void delmaxnode(LinkList *&L)
{
	LinkList *p=L->next,*pre=L,*maxp=p,*maxpre=pre;
	while (p!=NULL)					//用p扫描整个单链表,pre始终指向其前驱节点
	{
		if (maxp->data<p->data)		//若找到一个更大的节点
		{	maxp=p;					//更改maxp
			maxpre=pre;				//更改maxpre
		}
		pre=p;						//p、pre同步后移一个节点
		p=p->next;
	}
	maxpre->next=maxp->next;		//删除*maxp节点
	free(maxp);						//释放*maxp节点
}
int main()
{
	LinkList *L;
	int n=10;
	ElemType a[]={1,3,2,9,0,4,7,6,5,8};
	CreateListR(L,a,n);
	printf("L:");DispList(L);
	printf("删除最大值节点\n");
	delmaxnode(L);
	printf("L:");DispList(L);
	DestroyList(L);
	return 0;
}

两个文件需要在同一文件夹下,否则需要标示路径

今天就二级博客了,surprise,链表学会了,看见成长了

猜你喜欢

转载自blog.csdn.net/Waybyway/article/details/83449668