用c语言实现数据结构——单链表

单链表

用通俗的语言来说,单链表就像是头和尾没有连接起来的自行车链,每一个节点都是独立的,却又相互联系。特点:地址不连续,但是又相互有联系。

创建链表

1.头插法:
(1)为了操作方便,一般情况下,链表的头节点是不存放数据的。
(2)如果输入1 2 3 4,那么输出是 4 3 2 1,是相反的。从这里我们就有了头插法的思路,首先让头节点(head)和第一个新的节点连接(temp1)。之后的新节点(temp2)要插入到第一个新节点(temp1)的前面。在图中的表现如下:
第一步:让头指针和第一个temp连接起来:
用c语言实现数据结构——单链表_第1张图片
第二步:第二个temp连接到第一个temp的前面:
用c语言实现数据结构——单链表_第2张图片

第三步:头节点和第二个temp连接(头连temp):
用c语言实现数据结构——单链表_第3张图片
最后一步就是头节点和第一个temp断开:
用c语言实现数据结构——单链表_第4张图片
后续就以此类推了。
代码如下:

temp->next = head->next;
head->next = temp;

2.尾插法:
(1)头节点依旧不存放数据
(2)如果输入 1 2 3 4,那么就输出 1 2 3 4,思路:需要一个节点指针tail,可以理解为游标,防止头指针丢失的。一开始只有一个节点的时候,链表的头和尾是一样的。所以一开始会有tail=head。
第一步:头和尾指向同一个位置:
用c语言实现数据结构——单链表_第5张图片
第二步:尾和新节点temp连接:
用c语言实现数据结构——单链表_第6张图片

第三步:新节点temp成为新的尾巴:
用c语言实现数据结构——单链表_第7张图片

后续就以此类推了
代码如下:

tail->next = temp;/*先连接两个节点*/
tail = tail->next;/*尾指针后移*/

当你能看懂创建链表的时候,后面的基本操作基本也都会了,要说的也就是删除这里了。

删除对应位置节点

原理:找到要删除的位置的节点的前一个节点,然后让删除位置前一个节点的next指针指向它的下下个节点,接着释放掉删除位置的节点。这就完成了删除操作。

图解:
用c语言实现数据结构——单链表_第8张图片
假如我要删除第2个节点,那么我就要用一个指针遍历到第1个节点:
用c语言实现数据结构——单链表_第9张图片
这个时候节点1和节点3直接连接起来:
用c语言实现数据结构——单链表_第10张图片
最后释放掉节点2,这就相当于本来你和你女朋友拉着手呢,结果来了另一个比你帅比你有钱的男孩,拉走了你的女朋友,然后你被抛弃了哈哈哈。
用c语言实现数据结构——单链表_第11张图片
代码如下:

/*
Function name :deleteNode
Description : 指定位置删除节点
Parameter   : 
              @head : 单链表的头指针
			  @i    : 要删除的位置
return      : 返回1成功,返回其他失败
*/
int deleteNode(Node *head, int i)
{
     
	Node *temp = head;/*防止头指针丢失*/
	int num = getNum(head);/*获取链表长度*/
	if (i<1 || i>num) return 0;/*删除位置不合法*/

	for (int k = 0; k < i - 1; k++)/*temp指针移到要删除的节点前*/
	{
     
		temp = temp->next;
	}
	Node *willDelete = temp->next;/*要删除的节点*/
	temp->next = willDelete->next;/*隔着要删除的节点连接*/
	free(willDelete);/*释放要删除的节点*/
	return 1; 
}

完整代码,注释和运行结果

讲在前面,如果你了解单链表的基本原理,那么这个代码看起来会很轻松。

/*********************************************
@File name : singleChainList.c
@Author : StudyCcYa
@Version : 1.0
@Date : 2020-11-08
@Description : 用c语言实现数据结构——单链表
********************************************/
#include 
#include 
#include 


typedef int Type;

/*单链表节点的结构体*/
typedef struct Node
{
     
	Type data;/*单链表的数据*/
	struct Node *next;/*用于指向下一个节点的结构体指针*/
}Node;

Node *initNode();/*初始化单链表节点*/
Node *emptyNode();/*创建一个空的节点*/
Node *creatListHead();/*头插法创建一个单链表*/
Node *creatListTail();/*尾插法创建一个单链表*/
int printList(Node *head);/*输出单链表中的所有节点*/
int getNum(Node *head);/*统计节点个数*/
int insertElem(Node *head, int i,Type elem);/*指定位置增加(插入)数据*/
int deleteNode(Node *head, int i);/*指定位置删除节点*/
Type getNode(Node *head, int i);/*查找指定位置的数据*/
int changeNode(Node *head, int i,Type elem);/*修改指定位置的数据*/

/*
Function name : initNode
Description : 初始化单链表节点
Parameter : 
           无
return   : 返回一个单链表节点,否则失败
*/
Node *initNode()
{
     
	Node *temp = (Node *)malloc(sizeof(Node));/*申请一个节点的空间*/
	assert(temp);/*断言,如果申请空间失败则报错*/
	temp->data = 0;
	temp->next = NULL;
	return temp;
}

/*
Function name : emptyNode
Description : 创建一个空的节点
Parameter : 
            无
return    : 返回一个空的单链表节点,否则失败
*/
Node *emptyNode()
{
     
	Node *temp = (Node *)malloc(sizeof(Node));/*申请一个节点的空间*/
	assert(temp);
	temp->next = NULL;
	return temp;
}

/*
Function name : creatList
Description : 头插法创建一个单链表
Parameter :
            无
return   : 返回一个单链表的头指针,其他失败
*/
Node *creatListHead()
{
     
	int n;
	Type elem;
	Node *head = emptyNode();/*头指针不存放数据*/
	printf("请输入要创建链表节点的数量(头插):\n");
	scanf("%d",&n);
	printf("请输入数据:\n");
	for (int i = 0; i < n; i++)
	{
     
		Node *temp = initNode();
		scanf("%d",&temp->data);
		temp->next = head->next;/*新节点的next指针和头节点的next的指针指向同一位置*/
		head->next = temp;/*连接*/
	}
	return head;
}

/*
Function name : creatListTail
Description : 尾插法创建单链表
Parameter :
@head : 单链表的头指针
return     : 返回一个头指针,返回其他失败
*/
Node *creatListTail()
{
     
	Node *head = emptyNode();/*头指针不存放数据*/
	Node *tail = head;/*一开始头尾指向位置一样*/
	int n;
	printf("请输入要创建链表节点的数量(尾插):\n");
	scanf("%d", &n);
	printf("请输入数据:\n");
	for (int i = 0; i < n; i++)
	{
     
		Node *temp = initNode();
		scanf("%d", &temp->data);
		tail->next = temp;/*先连接两个节点*/
		tail = tail->next;/*尾指针后移*/
	}
	return head;
}

/*
Function name : printList
Description : 输出单链表
Parameter : 
            @head : 单链表的头指针
return    : 返回1成功,返回其他失败
*/
int printList(Node *head)
{
     
	Node *temp = head->next;/*临时链表指针,防止头指针丢失*/
	for (; temp != NULL; temp = temp->next)/*循环遍历链表*/
	{
     
		if (temp->next != NULL)/*没有到最后一个节点*/
		{
     
			printf("%d->", temp->data);
		}
		if (temp->next == NULL)/*到最后一个节点*/
		{
     
			printf("%d\n",temp->data);
			return 1;/*输出成功*/
		}
	}
	return 0;
}

/*
Function name : getNum
Description : 统计节点个数
Parameter :
           @head : 单链表的头指针
return    : 返回单链表节点的个数,返回其他失败
*/
int getNum(Node *head)
{
     
	int i = 0;/*用于计数*/
	Node *temp = head->next;/*第一个节点不算*/
	while (temp!=NULL)
	{
     
		i++;
		temp = temp->next;
	}
	return i;
}

/*
Function name :insertElem
Description : 指定位置增加(插入)数据
Parameter : 
           @head: 单链表的头指针
		   @i   : 插入的位置
		   @elem: 插入的数据
return    : 返回1成功,其他失败
*/
int insertElem(Node *head, int i,Type elem)
{
     
	Node *temp = head;
	int num = getNum(head);/*获取单链表的长度*/
	if (i<1 || i>num+1) return 0;/*插入位置不合法*/
	//if (i == 1) /*如果在最前面插入*/
	//{
     
	//	Node *newNode = initNode();
	//	newNode->data = elem;//赋值
	//	newNode->next = temp->next;/*这里相当于一个头插*/
	//	temp->next = newNode;
	//	return 1;
	//}
	//if (i >= 1 && i <= num)/*如果在中间插入*/
	//{
     
		for (int k = 0; k < i-1; k++)/*temp指针移到要插入的节点前,这个时候就体现出头节点不保存数据的好处了*/
		{
     
			temp = temp->next;
		}
		/*下面的代码段就跟上面一样了*/
		Node *newNode = initNode();
		newNode->data = elem;
		newNode->next = temp->next;
		temp->next = newNode;
		return 1;
	//}
	return 0; /*表示插入失败咯*/
	/*插到最后的情况是跟中间一样的。所以不再做处理*/
}

/*
Function name :deleteNode
Description : 指定位置删除节点
Parameter   : 
              @head : 单链表的头指针
			  @i    : 要删除的位置
return      : 返回1成功,返回其他失败
*/
int deleteNode(Node *head, int i)
{
     
	Node *temp = head;/*防止头指针丢失*/
	int num = getNum(head);/*获取链表长度*/
	if (i<1 || i>num) return 0;/*删除位置不合法*/

	for (int k = 0; k < i - 1; k++)/*temp指针移到要删除的节点前*/
	{
     
		temp = temp->next;
	}
	Node *willDelete = temp->next;/*要删除的节点*/
	temp->next = willDelete->next;/*隔着要删除的节点连接*/
	free(willDelete);/*释放要删除的节点*/
	return 1; 
}

/*
Function name : getNode
Description : 查找指定位置的数据
Parameter : 
            @head : 单链表的头指针
			@i    : 要查找的位置
return    : 返回1成功,返回其他失败
*/
Type getNode(Node *head, int i)
{
     
	Node *temp = head;/*防止头指针丢失*/
	int num = getNum(head);/*获取单链表长度*/
	if (i<1 || i>num) return 0;/*查找位置不合法*/
	for (int k = 0; k < i; k++)/*temp指针移动到要查找的节点*/
	{
     
		temp = temp->next;
	}
	return temp->data;/*将数据返回到函数*/
}

/*
Function name : changeNode
Description   : 修改指定位置的数据
Parameter     :
                @head : 单链表的头指针
				@i    : 修改的位置
				@elem : 替换的数据
return        : 返回1成功,其他失败
*/
int changeNode(Node *head, int i, Type elem)
{
     
	Node *temp = head;/*防止头指针丢失*/
	int num = getNum(head);/*获取单链表长度*/
	if (i<1 || i>num) return 0;/*修改位置不合法*/
	for (int k = 0; k < i; k++)/*temp指针移动到要修改的节点*/
	{
     
		temp = temp->next;
	}
	temp->data = elem;/*替换数据*/
	return 1;
}

int main()
{
     
	Node *head = creatListHead();/*头插法*/
	printList(head);/*输出头插链表*/
	Node *head1 = creatListTail();/*尾插法*/
	printList(head1);/*输出尾插链表*/

	printf("增:\n");
	insertElem(head, 1, 66);/*第1个位置插入66*/
	printList(head);

	insertElem(head, 3, 77);/*中间位置插入77*/
	printList(head);

	insertElem(head, 8, 99);/*最后位置插入99*/
	printList(head);
	printf("删:\n");
	deleteNode(head, 1);/*删除第一个节点*/
	printList(head);

	deleteNode(head, 3);/*删除中间节点*/
	printList(head);

	deleteNode(head, 6);/*删除最后节点*/
	printList(head);

	printf("查:\n");
	printf("1:%d\n", getNode(head, 1));/*查询第1个节点的数据*/
	printf("2:%d\n", getNode(head, 2));/*查询中间节点的数据*/
	printf("5:%d\n", getNode(head, 5));/*查询最后节点的数据*/

	printf("改:\n");
	changeNode(head, 1, 22);/*第1个节点数据改成22*/
	printList(head);

	changeNode(head, 3, 33);/*中间节点数据改成33*/
	printList(head);

	changeNode(head, 5, 44);/*最后节点数据改成44*/
	printList(head);
	return 0;
}

用c语言实现数据结构——单链表_第12张图片
运行成功。

如有不足和建议,欢迎指正和讨论。后续会将所有的数据结构用c语言和java语言实现。

你可能感兴趣的:(用c语言实现数据结构,链表,数据结构,c语言,编程语言)