静态链表和动态链表

1. 静态链表和动态链表的区别:

(1)静态链表放在栈区

(2)动态链表放在堆区,堆区数据必须要手工开辟,手工释放

2. 单链表定义

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

struct LinkNode
{
	int num;  //数据域
	struct LinkNode * next;  //指针域
}

3. 静态链表的创建方法及使用

struct LinkNode node1 = {10, NULL};
struct LinkNode node2 = {20, NULL};
node1.next = &node2;  //建立结点之间的关系
struct LinkNode * pCurrent = &node1;
while(pCurrent != NULL)   //遍历链表
{
	printf("%d\n", pCurrent->num);  //打印结点中的数据
	pCurrent = pCurrent->next;
}

4. 动态链表的创建方法及使用

struct LinkNode * node1 = malloc(sizeof(struct LinkNode));
struct LinkNode * node2 = malloc(sizeof(struct LinkNode));
node1->next =node2;  //建立结点之间的关系
struct LinkNode * pCurrent = node1;
while(pCurrent != NULL)   //遍历链表
{
	printf("%d\n", pCurrent->num);  //打印结点中的数据
	pCurrent = pCurrent->next;
}
free(node1);
free(node2);

5. 常用约定:头结点不保存数据域,只保存指针域的一个空结点。

设定空头结点的好处:空头结点便于头插,头部插入数据方便,头结点永远不会变!


6. 动态链表的相关操作(函数)

(1)初始化链表,让用户拿到一个链表的头结点

struct LinkNode * initLinkList()
{
	//创建头结点
	struct LinkNode * pHeader = malloc(sizeof(struct LinkNode));
	if(pHeader != NULL)
	{
		return NULL;
	}
	pHeader->next = NULL;  //初始化头结点
	
	// 让用户初始化链表
	//专门用于维护当前链表中的尾节点,好处在于添加数据方便
	struct LinkNode * pTail = pHeader; //这句很重要!!!!
	int val = -1;
	while(1)
	{
		printf("请输入链表中的数据,-1代表输入结果\n");
		scanf("%d",&val);
		if(val == -1)
		{
			break;
		}
		//创建新结点	
		struct LinkNode * newNode = malloc(sizeof(struct LinkNode));
		newNode->num = val;
		newNode->next = NULL;
		
		//更改指针的指向
		pTail->next = newNode;  //相当于当前链表的最后一个结点的指针指向了当前新创建的结点
		pTail = newNode;//使pTail指向当先新建的结点。即永远指向最后一个结点
	}
	return pHeader;
}

(2)动态链表的遍历

void foreachList(struct LinkNode * pHeader)
{
	if(pHeader == NULL)
	{
		return;
	}
	struct LinkNode * pCurrent = pCurrent->next; 
	while(pCurrent != NULL)   //遍历链表
	{
		printf("%d\n", pCurrent->num);  //打印结点中的数据
		pCurrent = pCurrent->next;
	}
}

(3)动态链表插入结点

void insertList(struct LinkNode * pHeader, int oldVal, int newVal)
{
	//在oldVal后面插入newVal
	if(pHeader == NULL)
	{
		return;
	}
	//创建两个临时辅助指针
	struct LinkNode * pPrev = pHeader;
	struct LinkNode * pCurrent = pHeader->next;
	while(pCurrent != NULL) 
	{
		//用户传入的数据和遍历的链表中的数据一样
		if(pCurrent->num == oldVal)  //找到了
		{
			break;
		}
		//没找到,两个指针往后移
		pPrev = pCurrent;
		pCurrent = pCurrent->next;
	}
	//创建新结点
	struct LinkNode * newNode = malloc(sizeof(struct LinkNode));
	newNode->num = newVal;
	newNode->next = NULL;
	
	//更改指针的指向
	newNode->next = pCurrent;  
	pPrev->next = newNode;
}

(4)删除动态链表中一个结点

void deleteList(struct LinkNode * pHeader, int Val)
{
	if(pHeader == NULL)
	{
		return;
	}
	//创建两个临时辅助指针
	struct LinkNode * pPrev = pHeader;
	struct LinkNode * pCurrent = pHeader->next;
	while(pCurrent != NULL) 
	{
		//用户传入的数据和遍历的链表中的数据一样
		if(pCurrent->num == Val)  //找到了
		{
			break;
		}
		//没找到,两个辅助指针往后移
		pPrev = pCurrent;
		pCurrent = pCurrent->next;
	}
	//如果链表中没有用户传入的Val值,直接return
	if(pCurrent == NULL)
	{
		return;
	}
	
	//链表中有用户传入的Val值且已经找到,更改指针的指向
	pPrev->next = pCurrent->next;
	
	//删除结点并释放堆区数据
	free(pCurrent);  
	pCurrent = NULL;  //严谨的写法,防止野指针出现
}

(5)清空一个动态链表

注意:清空一个动态链表 是 把所有有数据的结点释放掉,还留着一个头结点,并没有将链表销毁掉,还可以从头插入数据。

void clearList(struct LinkNode * pHeader)
{
	if(pHeader == NULL)
	{
		return;
	}
	//创建1个临时辅助指针
	struct LinkNode * pCurrent = pHeader->next; //指向第一个有效数据的结点
	while(pCurrent != NULL) 
	{
		//先保存住下一个结点的位置
		struct LinkNode * nextNode = pCurrent->next;
		
		//删除当前结点并释放堆区数据
		free(pCurrent);  
		pCurrent = nextNode;
	}
	pHeader->next = NULL;
}

(6)销毁链表

注意:销毁链表 是 将链表销毁掉,头结点也没了。

void destroyList(struct LinkNode * pHeader)
{
if(pHeader == NULL)
	{
		return;
	}
	
	//先清空链表
	clearList(pHeader);
	
	//将头结点也释放掉
	free(pHeader);  
	pHeader = NULL;
}

(7)翻转链表

void reverList(struct LinkNode * pHeader)
{
	if(pHeader == NULL)
	{
		return;
	}
	//创建三个临时辅助指针
	struct LinkNode * pPrev = NULL;
	struct LinkNode * pCurrent = pHeader->next;
	struct LinkNode * pNext = NULL;
	
	while(pCurrent != NULL) 
	{
		
		pNext = pCurrent->next;  //pNext存储当前结点的下一个结点
		pCurrent->next = pPrev;  
		
		//移动辅助指针
		pPrev =pCurrent;  //pPrev永远指向翻转后链表的第一个结点
		pCurrent = pNext; //pCurrent永远指向剩下没有翻转的链表的第一个结点
	}
	pHeader->next = pPrev;
}

 

  • 1
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值