基本数据结构——单链表

文章简介:基本数据结构系列讲解之单链表(附源码)

 

1.介绍链表结构

链表中的每个结点都应包括以下两个部分。

(1)数据部分:保存结点的数据

(2)地址部分:保存下一结点地址

链表的头指针指向链表结构的第一个结点,依次直到最后一个结点,最后一个结点的地址部分一般放一个空指针NULL。

在链表结构中,通过指针实现结点的逻辑相邻,而逻辑相邻的结点在内存中不一定相邻,所以使用链表时不需要事先分配一块存储空间,程序员通过malloc函数动态分配结点的存储空间,当删除某结点时,再用free函数释放空间。

链表结构的缺点是浪费存储空间,因为每一个结点都需要额外存储一个指针变量。

链表有单链表、双向链表、循环链表等几类,本文主要讲解单链表的相关操作。

 

2.定义链表及数据元素类型

本程序的功能是通过单链表存储学生信息,学生信息包括:学号key,姓名name,年龄age。学生信息作为数据元素类型Data,链表数据结构CLType,在CLType内用Data类型变量表示数据部分,用链表结构的指针指向下一结点。

typedef struct
{
	char key[10];
	char name[15];
	int age;
}Data;

typedef struct Node
{
	Data nodeData;
	struct Node *nextNode;
}CLType;


3.添加结点

添加结点即在链表的尾部加入结点,操作步骤如下:

(1)分配内存空间,用以保存将要添加的结点;

(2)从头指针head开始检查,找到最后一个结点;

(3)将表尾结点的地址设置为新增结点地址;

(4)将新增结点的地址设置为NULL。

程序使用malloc为新增结点申请内存空间。

CLType *CLAddEnd(CLType *head,Data nodeData)
{
	CLType *node,*temp;
	if(!(node=(CLType*)malloc(sizeof(CLType))))
	{
		printf("内存申请失败!\n");
		return NULL;
	}
	else
	{
		node->nodeData=nodeData;
		node->nextNode=NULL;
		if(head=NULL)
		{
			head=node;
			return head;
		}
		temp=head;
		while(temp!=NULL)
		{
			temp=temp->nextNode;
		}
		temp->nextNode=node;
		return head;
	}
}

4.插入头结点

在链表首部插入结点,步骤如下:

(1)分配内存空间,用以保存新增结点;

(2)将新增结点指向head所指的结点;

(3)使head指向新增结点。 


CLType *CLAddFist(CLType *head,Data nodeData)
{
	CLType *node;
	if(!(node=(CLType *)malloc(sizeof(CLType))))
	{
		printf("内存分配失败!\n");
		return NULL;
	}
	else
	{
		node->nodeData=nodeData;
		node->nextNode=head;
		head=node;
		return head;
	}
}


5.查找结点

通过关键字key来查找结点,使用strcmp函数比较查找,找到后返回该结点指针。

 

CLType *CLFindNode(CLType *head,char *key)
{
	CLType *temp;
	temp=head;
	while(temp)
	{
		if(strcmp(temp->nodeData.key,key)==0)
		{
			return temp;
		}
	temp=temp->nextNode;
	}
	return NULL;
}


6.插入结点

链表中插入结点步骤如下:

(1)分配内存空间,用以保存新的结点;

(2)找到要插入的位置;

(3)将插入的结点指向插入位置指向的结点,插入位置指向新增结点。

本程序使用关键字找到要插入的位置。


CLType *CLInsertNode(CLType *head,char *key,Data nodeData)
{
	CLType *node,*temp;
	if(!(node=(CLType *)malloc(sizeof(CLType))))
	{
		printf("内存申请失败!\n");
		return 0;
	}
	node->nodeData=nodeData;
	temp=CLFindNode(head,key);
	if(temp)
	{
		node->nextNode=temp->nextNode;
		temp->nextNode=node;
	}
	else
	{
		printf("插入的位置不对!\n");
		free(node);
	}
	return head;
}

7.删除结点

链表中删除结点的操作如下:

(1)找到要删除的目标结点;

(2)使该结点的前一个结点指向后一个结点;

(3)删除该结点。

 

int CLDeleteNode(CLType *head,char *key)
{
	CLType *node,*temp;
	temp=head;
	node=head;
	while(temp)
	{
		if(strcmp(temp->nodeData.key,key)==0)
		{
			node->nextNode=temp->nextNode;
			free(temp);
			return 1;
		}
		else
		{
			node=temp;
			temp=temp->nextNode;
		}
	}
	return 0;
}


8.计算链表长度

由于链表不是在内存中不是连续存储的,所以需要遍历整个链表才能计算出链表长度。

 

int CLLength(CLType *head)
{
	int len=0;
	CLType *temp;
	temp=head;
	while(temp)
	{
		len++;
		temp=temp->nextNode;
	}
	return len;
}


9.显示所有结点


void CLAllNode(CLType *head)
{
	CLType *temp;
	Data nodeData;
	temp=head;
	printf("当前共有%d个结点。链表所有数据如下:\n",CLLength(head));
	while(temp)
	{
		nodeData=temp->nodeData;
		printf("结点(%s,%s,%d)\n",nodeData.key,nodeData.name,nodeData.age);
		temp=temp->nextNode;
	}
}


 

本文源代码:单链表操作.cpp

 

 

 

 


你可能感兴趣的:(数据结构,c,单链表)