单链表完整实现

Posted gmengshuai

tags:

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

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

/* 定义结构体 */
typedef struct Node
{
	int data;			//数据域
	struct Node * pNext;//指针域
}NODE, * PNODE;         //由于使用了typedef, 所以NODE <=> struct Node  ,  PNODE <=> struct Node * 


/* 函数声明 */
void test01();
PNODE create_list();				//创建一个链表
void traverse_list(PNODE pHead);	//遍历整个链表并输出
bool is_empty(PNODE pHead);			//判断链表是否为空
int length_list(PNODE pHead);		//链表的长度
bool insert_list(PNODE pHead, int pos, int value);	//链表的插入
bool delete_list(PNODE pHead, int pos, int * pval);	//链表的删除
void sort_list(PNODE pHead);		//链表的排序
/* 主函数 */
int main()
{
	test01();
	
	return 0;
}

/* 调用函数 */

void test01()
{
		PNODE pHead = NULL;  //头指针为空,用来保存头结点的地址
	int val;			 //用来保存删除的元素

	pHead = create_list(); //创建一个链表,并返回头结点的地址给pHead

	traverse_list(pHead);  //遍历整个链表

	if(is_empty(pHead))	   //判断链表是否为空
	{
		printf("链表为空
");
	}
	else
	{
		printf("链表不空
");
	}

	int len = length_list(pHead);
	printf("链表的长度为:%d

", len);

	sort_list(pHead);
	printf("链表排序后");
	traverse_list(pHead);

	insert_list(pHead, 2, 66);
	printf("链表插入后");
	traverse_list(pHead); 

	if( delete_list(pHead, 2, &val) )
	{
		printf("删除成功,您删除的元素是:%d
", val);
	}
	else
	{
		printf("删除失败!您删除的元素不存在!
");
	}
	printf("链表删除后");
	traverse_list(pHead); 

} 
/*———————————————————————————————————————————————————————*/
PNODE create_list()
{
	int len;      //用来存放有效节点的个数
	int i;
	int temp_val; //临时存放用户输入结点数据域的值
	PNODE pNew; 

	//分配一个不存放有效数据的头结点
	PNODE pHead = (PNODE)malloc(sizeof(NODE));

	if(NULL == pHead)
	{
		printf("分配失败,程序终止!");
		exit(-1);
	}

	PNODE pTemp = pHead; //临时存放头结点的地址
	pTemp->pNext = NULL;

	printf("请输入您要生成的链表节点的个数: len = ");
	scanf("%d", &len);

	for(i = 0; i<len; i++)
	{
		printf("请输入第%d个节点数据域的值 :", i+1);
		scanf("%d", &temp_val);
		
		//循环一次分配一个存放有效数据的结点
		pNew = (PNODE)malloc(sizeof(NODE));
		if(NULL ==pNew)
		{
			printf("分配失败,程序终止!");
			exit(-1);
		}

		pNew->data = temp_val;
		//尾插法 
		pTemp->pNext = pNew;
		pNew->pNext = NULL;  //每分配一个结点,这个结点就是最后一个,所以它的指针域(pNext)为空
		pTemp = pNew;        //保证前一个结点的指针域都指向后一个结点
	}

	return pHead;  //返回头结点的地址

}
/*———————————————————————————————————————————————————————*/

void traverse_list(PNODE pHead)
{
	PNODE p = pHead->pNext;  //头结点的指针域赋给p,即首结点赋给p 【注意区分头结点和首结点】

	printf("链表的数据为:
");
	while(NULL != p)
	{
		printf("%d ", p->data);
		p = p->pNext;        //下一个结点赋给p
	}

	printf("

");

	return;
}
/*———————————————————————————————————————————————————————*/

bool is_empty(PNODE pHead)
{
	if(NULL == pHead->pNext)
	{
		return true;
	}
	else
	{
		return false;
	}
}
/*———————————————————————————————————————————————————————*/

int length_list(PNODE pHead)
{
	PNODE p = pHead->pNext;//pNext是struct Node * 类型,p也应该是struct Node * 类型
	int count = 0;

	while(NULL != p)       //只要指针域指向的不是空结点就不结束
	{
		count++;
		p = p->pNext;
	}

	return count;
}
/*———————————————————————————————————————————————————————*/
//数组与链表存储方式虽不同,但是它们的算法是一样的
void sort_list(PNODE pHead)
{
	//数组排序
/*
	int i, j, t;
	int len = length_list(pHead);

	for(i = 0; i<len; i++)
	{
		for(j = i+1; j<len; j++)
		{
			if(a[i]>a[j])
			{
				t = a[i];
				a[i] = a[j];
				a[j] = t;
			}
		}
	}
*/	

	//链表排序

	int t;
	PNODE p, q;
	
	for(p = pHead->pNext; NULL != p; p = p->pNext)//由于最后一个结点的指针域为空,所以可作为循环结束的条件
	{
		for(q = p->pNext; NULL != q; q = q->pNext)//注意和数组进行比较,思想都是一样的
		{
			if(p->data>q->data)
			{
				t = p->data;
				p->data = q->data;
				q->data = t;
			}
		}
	}

	return;
}

/*———————————————————————————————————————————————————————*/
//链表的插入不存在满的情况 
//在pHead所指向链表的第pos个节点的前面插入一个新的结点,假定pos为3
bool insert_list(PNODE pHead, int pos, int value)
{
	int i = 0;
	PNODE p = pHead;

	while(NULL != p && i<pos-1) //i<3-1=2, 取值为0、1,循环执行了两次,p指向了第二个有效结点
	{
		p = p->pNext;
		i++;
	}

	if(NULL == p || i>pos-1)
	{
		return false;
	}

	//如果程序能执行到这一行说明p已经指向了第pos-1个结点,但第pos-1个节点是否存在无所谓
	//分配需要插入的结点
	PNODE pNew = (PNODE)malloc(sizeof(NODE));
	if(NULL == pNew)
	{
		printf("动态分配内存失败!");
		exit(-1);
	}
	pNew->data = value;

	//将新的结点存入p节点的后面【即第pos个节点的前面】,若没明白请回头学习如何插入节点
	PNODE q;
	q = p->pNext;
	p->pNext = pNew;
	pNew->pNext = q;

	return true;
}
/*———————————————————————————————————————————————————————*/

//删除第pos个结点,假定pos为3
bool delete_list(PNODE pHead, int pos, int * pval)
{
	int i = 0;
	PNODE p = pHead;

	while(NULL != p->pNext && i<pos-1)//i<3-1=2, 取值为0、1,循环执行了两次,p指向了第二个结点
	{
		p = p->pNext;
		i++;
	}

	if(NULL == p->pNext && i>pos-1)
	{
		return false;
	}

	//如果程序能执行到这一行说明p已经指向了第pos-1个结点,并且第pos个节点是存在的
	//这里的指向解释一下:通俗的说就是等于这个结点的意思

	PNODE q = p->pNext; //q指向待删除的结点

	*pval = q->data;    //返回删除的值

	//删除p节点后面的结点,若没明白请回头学习如何删除节点
	p->pNext = p->pNext->pNext;
	free(q);			//释放q所指向的节点所占的内存
	q = NULL;			//q = p->pNext = NULL,表示p指针域指向的结点已被删除
	
	return true;
}
/*———————————————————————————————————————————————————————*/

以上是关于单链表完整实现的主要内容,如果未能解决你的问题,请参考以下文章

单链表完整实现

单链表

Java实现单链表(步骤详解+源码)

单链表基本操作

数据结构代码(用C语言) 单链表的插入和删除

单链表~增删查改(附代码)~简单实现