数据结构-链表的操作

Posted 坏坏-5

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构-链表的操作相关的知识,希望对你有一定的参考价值。


链表综合程序

主函数

# include <stdio.h>
# include <malloc.h>  //使用了malloc函数
# include <stdlib.h>  //使用了exit函数

typedef struct Node
{
	int data;              //数据域
	struct Node * pNext;   //指针域
}NODE, *PNODE;   //NODE等价于struct Node,PNODE等价于struct Node *

/*函数声明,可以不写形参名,但是必须声明形参类型*/
PNODE Create_list(void);               //创建链表
void Traverse_list(PNODE);             //遍历链表
bool Is_empty(PNODE);                  //判断链表是否为空
int Length_list(PNODE);                //判断链表的长度
bool Insert_list(PNODE, int, int);     //在链表中插入元素
bool Delete_list(PNODE, int, int *);   //删除链表中的元素
void Sort_list(PNODE);                 //对链表中的数据排序

int main(void)
{
	PNODE pHead = NULL;
	int val;  //用于保存被删除的元素

	printf("----------------创建链表----------------\\n");
	pHead = Create_list();    //创建链表

	printf("\\n----------------遍历链表----------------\\n");
	printf("链表中的元素为:\\n");
	Traverse_list(pHead);     //遍历链表

	printf("------------判断链表是否为空------------\\n");
	if(Is_empty(pHead))       //判断链表是否为空
		printf("链表为空!\\n");
	else
		printf("链表非空!\\n");

	printf("----------------插入元素----------------\\n");
	Insert_list(pHead, 3, 25);      //链表插入结点
	printf("链表中的第3个位置插入元素25后,链表为:\\n");
	Traverse_list(pHead);

	printf("----------------元素排序----------------\\n");
	Sort_list(pHead);  //对链表中的元素进行排序
	printf("对链表中的元素进行排序后为:\\n");
	Traverse_list(pHead);

    printf("--------------判断链表长度--------------\\n");
	int len = Length_list(pHead);   //判断链表长度
	printf("链表长度为:%d\\n", len);

	printf("----------------删除元素----------------\\n");
	if(Delete_list(pHead, 2, &val))  //删除链表中的第2个元素
		printf("删除的是第2个元素:%d\\n删除成功!\\n", val);
	else
		printf("删除失败!\\n");
	printf("删除后链表中的元素为:\\n");
	Traverse_list(pHead);

	return 0;
}

创建链表函数

/*创建非循环单链表,并将该链表的首结点地址返回*/
PNODE Create_list(void)
{
	int len;    //用于存放有效结点的个数
	int i;
	int val;    //用于临时存放用户输入的结点的值

	/*分配不存放有效数据的头指针*/
	PNODE pHead = (PNODE)malloc(sizeof(NODE)); 
	/*
	    定义一个PNODE(struct Node *)类型的变量pHead,
	    pHead由malloc函数分配内存空间,所占大小为
	    NODE(struct Node)所占大小
	*/
	
	/*判断内存是否分配成功,未成功分配内存则终止程序*/
	if (NULL == pHead)
	{
		printf("分配失败!程序终止!\\n");
		exit(-1);  //终止程序
	}

	/*分配存储最后一个尾结点的指针*/
	PNODE pTail = pHead;  
	pTail->pNext = NULL;

	/*用户输入链表的长度*/
	printf("请输入您需要生成的链表结点个数:");
	scanf("%d", &len);

	/*用户输入每一个结点的数据*/
	for (i = 0; i < len; i++)
	{
		printf("请输入第 %d 个结点的值:", i + 1);
		scanf("%d", &val);

		/*新分配一个结点,用于临时存放用户输入的数据*/
		PNODE pNew = (PNODE)malloc(sizeof(NODE));
		if (NULL == pNew)
		{
			printf("分配失败!程序终止!\\n");
			exit(-1);  //终止程序
		}

		/*将之后每分配的结点挂在前一个结点后*/
		pNew->data = val;
		pTail->pNext = pNew;
		pNew->pNext = NULL;
		pTail = pNew;
	}

	return pHead;  //返回第一个存放有效数据的结点地址
}

创建链表

  • 使用malloc函数动态分配一个头指针(pHead),指向首结点
    • if语句判断头指针是否分配成功(NULL==pHead)
  • 使用malloc函数动态分配一个尾指针(pTail),指向尾结点
    • if语句判断尾结点是否分配成功(NULL==pHead)
  • 当链表中只有一个结点时,pTal就等于pHead,且指针域为空(NULL)
  • 使用for循环,对链表的长度以及元素进行赋值
    • 在循环体内,再动态分配一个临时结点(pNew),用于临时存放新加入结点的数据
    • 将用户输入的值赋值给pNew中的data,同时把pNew中的指针域清空(pNext=NULL)
    • 再使pTail中的pNext指向pNew,即将pNew挂在首结点后
    • 使pTail的值等于pNew,即pTail指向尾结点
  • 最后返回pHead,即存指向首结点的指针

遍历链表函数

/*遍历链表*/
void Traverse_list(PNODE pHead)
{
	PNODE p = pHead->pNext;  //定义结点的指针,pHead指向的下一个结点地址

    /*
        判断指向下一个结点地址是否为NULL,是则表明是最后一个结点
        否则输出这个结点中的数据部分,并使p指向下一个结点
    */
	while(NULL != p)
	{
		printf("%d ", p->data);
		p = p->pNext;
	}
	printf("\\n");

	return;
}

判断链表是否为空函数

/*判断链表是否为空*/
bool Is_empty(PNODE pHead)
{
    /*如果头指针指向的下一个结点为NULL,则表明链表中没有结点*/
	if (NULL == pHead->pNext)
		return true;
	else
		return false;
}

判断链表的长度函数

/*判断链表的长度*/
int Length_list(PNODE pHead)
{

    /*定义临时结点指针p,p指向首结点*/
	PNODE p = pHead->pNext;
	int len = 0;
	
	/*
	    判断p是否为空,为空则表明是最后一个结点,否则执行长度+1
	    同时把p指向下一个结点
	*/
	while(NULL != p)
	{
		++len;
		p = p->pNext;
	}

	return len;  //返回链表的长度
}

在链表中插入结点函数

/*向链表的第pos个结点前插入一个新的结点,值为val*/
bool Insert_list(PNODE pHead, int pos, int val)
{
	int i = 0;
	PNODE p = pHead;

	/*
	    pHead指向一个链表,并且插入的位置要大于0,即只能在1之后的位置插入结点,
	    包括1,不能在负数位置插入结点
	    
	    i用来统计链表的长度,插入的位置只能是链表长度的下一个结点,不能
	    是下下一个结点,即中间不能空一个结点
	*/
	while(NULL != p && i < pos - 1)
	{
		 p = p->pNext;
		 i++;
	}

	/*如果插入结点的位置大于链表长度+1,或p没有指向一个链表,返回false*/
	if (i > pos - 1 || NULL == p)
		return false;
	
	/*定义一个临时结点,用于存放用户输入的数据*/
	PNODE pNew = (PNODE)malloc(sizeof(NODE));
	if (NULL == pNew)
	{
		printf("动态内存分配失败!\\n");
		exit(-1);
	}

	/*将新分配的结点挂在链表上*/
	pNew->data = val;
	PNODE q = p->pNext;
	p->pNext = pNew;
	pNew->pNext = q;

	return true;
}

插入结点

  • 将插入结点的数据赋值给pNew中的data
  • 定义临时结点指针q,用于存放p原本指向的下一个结点
  • 将p中的pNext指向新分配的存放数据的临时结点(pNew)
  • 将pNew中的pNext指向q,即原本p指向的下一个结点

对链表中的数据排序函数

/*对链表中的元素进行排序*/
void Sort_list(PNODE pHead)
{
	int i, j, t;
	int len = Length_list(pHead);  //链表长度,用于判断比较的次数
	PNODE p, q;  //用于指向两个不同的结点,便于进行比较

	/*
	    p指向首结点,条件不成立,p则指向下一个结点
	    q指向p的下一个结点,条件不成立,q则指向下一个结点
	    i表示使用第i个结点,j表示与i进行比较的后续结点
	*/
	for (i = 0, p = pHead->pNext; i < len - 1; i++, p = p->pNext)
	{
		for (j = i + 1, q = p->pNext; j < len; j++, q = q->pNext)
		{
			/*
			    判断第i个结点中的数据是否大于第j个结点中的数据
			    是则互换数据部分,否则与第j个结点的下一个结点进行比较
			*/
			if (p->data > q->data)
			{
				t = p->data;
				p->data = q->data;
				q->data = t;
			}
		}
	}
	return;  //表示函数调用结束
}

删除链表中的结点函数

/*删除链表中pos位置的元素*/
bool Delete_list(PNODE pHead, int pos, int * pVal)
{
	int i = 0;
	PNODE p = pHead;

	/*
	    p不指向链表中的最后一个结点,
	    p指向删除位置前的一个结点
	*/
	while(NULL != p->pNext && i < pos - 1)
	{
		 p = p->pNext;
		 i++;
	}

	/*删除的位置大于链表的长度或者p是最后一个结点,返回false*/
	if (i > pos - 1 || NULL == p->pNext)
		return false;

	/*将删除后的结点挂在删除结点前的结点上*/
	PNODE q = p->pNext;  //定义临时结构体指针,存放删除结点的指针
	*pVal = q->data;  //把删除的数据存放在pVal中

	/*删除p结点后面的结点*/
	p->pNext = p->pNext->pNext;  //使p->pNext跳过被删除的结点,指向下一个结点
	free(q);  //将q结点,即被删除的结点存储空间释放
	q = NULL;  //使q为空

	return true;
}

删除结点

完整程序

/*
	1.创建链表
	2.遍历链表
	3.判断链表是否为空
	4.输出链表长度
	5.在链表中插入结点
	6.对链表中个结点中的数据进行排序
	7.删除链表中的结点
*/
# include <stdio.h>
# include <malloc.h>  //使用了malloc函数
# include <stdlib.h>  //使用了exit函数

typedef struct Node
{
	int data;              //数据域
	struct Node * pNext;   //指针域
}NODE, *PNODE;   //NODE等价于struct Node,PNODE等价于struct Node *

/*函数声明,可以不写形参名,但是必须声明形参类型*/
PNODE Create_list(void);               //创建链表
void Traverse_list(PNODE);             //遍历链表
bool Is_empty(PNODE);                  //判断链表是否为空
int Length_list(PNODE);                //判断链表的长度
bool Insert_list(PNODE, int, int);     //在链表中插入元素
void Sort_list(PNODE);                 //对链表中的数据排序
bool Delete_list(PNODE, int, int *);   //删除链表中的元素


int main(void)
{
	PNODE pHead = NULL;
	int val;  //用于保存被删除的元素

	printf("----------------创建链表----------------\\n");
	pHead = Create_list();    //创建链表

	printf("\\n----------------遍历链表----------------\\n");
	printf("链表中的元素为:\\n");
	Traverse_list(pHead);     //遍历链表

	printf("------------判断链表是否为空------------\\n");
	if(Is_empty(pHead))       //判断链表是否为空
		printf("链表为空!\\n");
	else
		printf("链表非空!\\n");

	printf("----------------插入元素----------------\\n");
	Insert_list(pHead, 3, 25);      //链表插入结点
	printf("链表中的第3个位置插入元素25后,链表为:\\n");
	Traverse_list(pHead);

	printf("----------------元素排序----------------\\n");
	Sort_list(pHead);  //对链表中的元素进行排序
	printf("对链表中的元素进行排序后为:\\n");
	Traverse_list(pHead);

    printf("--------------判断链表长度--------------\\n");
	int len = Length_list(pHead);   //判断链表长度
	printf("链表长度为:%d\\n", len);

	printf("----------------删除元素----------------\\n");
	if(Delete_list(pHead, 2, &val))  //删除链表中的第2个元素
		printf("删除的是第2个元素:%d\\n删除成功!\\n", val);
	else
		printf("删除失败!\\n");
	printf("删除后链表中的元素为:\\n");
	Traverse_list(pHead);

	return 0;
}

/*创建非循环单链表,并将该链表的首结点地址返回*/
PNODE Create_list(void)
{
	int len;    //用于存放有效结点的个数
	int i;
	int val;    //用于临时存放用户输入的结点的值

	/*分配不存放有效数据的头指针*/
	PNODE pHead = (PNODE)malloc(sizeof(NODE)); 
	/*
	    定义一个PNODE(struct Node *)类型的变量pHead,
	    pHead由malloc函数分配内存空间,所占大小为
	    NODE(struct Node)所占大小
	*/
	
	/*判断内存是否分配成功,未成功分配内存则终止程序*/
	if (NULL == pHead)
	{
		printf("分配失败!程序终止!\\n");
		exit(-1);  //终止程序
	}

	/*分配存储最后一个尾结点的指针*/
	PNODE pTail = pHead;  
	pTail->pNext = NULL;

	/*用户输入链表的长度*/
	printf("请输入您需要生成的链表结点个数:");
	scanf("%d", &len);

	/*用户输入每一个结点的数据*/
	for (i = 0; i < len; i++)
	{
		printf("请输入第 %d 个结点的值:", i + 1);
		scanf("%d", &val);

		/*新分配一个结点,用于临时存放用户输入的数据*/
		PNODE pNew = (PNODE)malloc(sizeof(NODE));
		if (NULL == pNew)
		{
			printf("分配失败!程序终止!\\n");
			exit(-1);  //终止程序
		}

		/*将之后每分配的结点挂在前一个结点后*/
		pNew->data = val;
		pTail->pNext = pNew;
		pNew->pNext = NULL;
		pTail = pNew;
	}

	return pHead;  //返回第一个存放有效数据的结点地址
}

/*遍历链表*/
void Traverse_list(PNODE pHead)
{
	PNODE p = pHead->pNext;  //定义结点的指针,pHead指向的下一个结点地址

    /*
        判断指向下一个结点地址是否为NULL,是则表明是最后一个结点
        否则输出这个结点中的数据部分,并使p指向下一个结点
    */
	while(NULL != p)
	{
		printf("%d ", p->data);
		p = p->pNext;
	}
	printf("\\n");

	return;
}


/*判断链表是否为空*/
bool Is_empty(PNODE pHead)
{
    /*如果头指针指向的下一个结点为NULL,则表明链表中没有结点*/
	if (NULL == pHead->pNext)
		return true;
	else
		return false;
}

/*判断链表的长度*/
int Length_list(PNODE pHead)
{

    /*定义临时结点指针p,p指向首结点*/
	PNODE p = pHead->pNext;
	int len = 0;
	
	/*
	    判断p是否为空,为空则表明是最后一个结点,否则执行长度+1
	    同时把p指向下一个结点
	*/
	while(NULL != p)
	{
		++len;
		p = p->pNext;
	}

	return len;  //返回链表的长度
}

/*向链表的第pos个结点前插入一个新的结点,值为val*/
bool Insert_list(PNODE pHead, int pos, int val)
{
	int i = 0;
	PNODE p = pHead;

	/*
	    pHead指向一个链表,并且插入的位置要大于0,即只能在1之后的位置插入结点,
	    包括1,不能在负数位置插入结点
	    
	    i用来统计链表的长度,插入的位置只能是链表长度的下一个结点,不能
	    是下下一个结点,即中间不能空一个结点
	*/
	while(NULL != p && i < pos - 1)
	{
		 p = p->pNext;
		 i++;
	}

	/*如果插入结点的位置大于链表长度+1,或p没有指向一个链表,返回false*/
	if (i > pos - 1 || NULL == p)
		return false;
	
	/*定义一个临时结点,用于存放用户输入的数据*/
	PNODE pNew = (PNODE)malloc(sizeof(NODE));
	if (NULL == pNew)
	{
		printf("动态内存分配失败!\\n");
		exit(-1);
	}

	/*将新分配的结点挂在链表上*/
	pNew->data = val;
	PNODE q = p->pNext;
	p->pNext = pNew;
	pNew->pNext = q;

	return true;
}

/*对链表中的元素进行排序*/
以上是关于数据结构-链表的操作的主要内容,如果未能解决你的问题,请参考以下文章

C语言反转单向链表的代码

认识链表以及其常见操作Java代码实现

数据结构算法——链表的各种操作

JavaScript单向链表的创建遍历插入删除操作

单链表基本操作

数据结构带头双向循环链表