线性表之链式存储结构_单链表相关算法

在存储结构上,不需要连续的存储空间,需要上一个结点的指针域 指向下一个结点即可,找到一个结点就可以找到下一个结点。

学习教材是大话数据结构,加上自己的一些个人理解。这个算法 有点绕,需要对指针 相关内容相当熟悉。通过学习感觉单链表相关算法还是蛮考验C知识的和逻辑思维。

下面看代码:


#include <stdio.h>
#include <stdlib.h>
#define	ERROR 0
#define OK 1
typedef int EleType;
typedef int Status;
typedef struct Node Node;

//链表元素
struct Node
{
	EleType data;//数据域
	Node * next;//指针域
};
typedef Node* LinkList;
void printLinkList(const LinkList * const list) {
	if (NULL ==list) {//链表为空
		printf("printLinkList error \n");
		return;
	}
	int i = 1;
	LinkList li = (*list)->next;//从头结点后面第一个结点开始遍历
	while (li)//最后一个元素没有指向,不会进行循环。
	{
		printf("第%d元素:%d\t", i, li->data);
		li = li->next;
		i++;
	}
	printf("\n");
	return;
}
//创建拥有头结点的链表
//头插法创建链表,往链表中添加元素,新创建的的元素始终在头结点后面类似 头指针 -> 头结点->An->An-1->An-2 ...-> A1
//元素的数据 随机生成100以内的数字
Status creatLinkListInHead(LinkList *list,int n) {
	srand(time(0));//设置随机种子,为产生随机数做准备。
	//LinkList 类型 和 Node * 类型是一样的!看最上方定义类型别名,为什么可以做呢?链表的头指针 就是指向结点Node,所有链表类型是 Node *,只是为了更好看而已。 
	LinkList li=NULL;
	Node *node=NULL;//可以定义为 LinkList *node = NULL;
	int i = 0;
	li = (LinkList)malloc(sizeof(Node));//头指针指向头结点,给头结点分配空间
	if (NULL == li||n<0) {//分配内存空间失败或者链表元素个数非法 返回
		return ERROR;
	}
	li->next = NULL;//初始头结点没有指向
	for ( i = 0; i < n; i++)
	{
		node = (Node*)malloc(sizeof(Node));//给结点分配空间
		if (NULL==node) {//给分配空间失败 
			return ERROR;
		}
		node->data = rand()%100;//除以100取余的到100以内的数字,不包括100,如果含100 就需要+1
		node->next = li->next;//新添加的元素指针域 指向头结点后面的结点
		li->next = node;//头结点指针域 指向新增加的元素

	}
	*list = li;//通过指针 给外部链表赋值
	return OK;
}
//尾插法创建链表,往链表中添加元素,先添加的元素放前面,后添加的元素放后面,遵循先来后到的道理
Status creatLinkListInTail(LinkList *list, int n) {
	srand(time(0));//设置随机种子
	LinkList li = NULL ;
	Node *node = NULL;
	int i = 0;
	li = (LinkList)malloc(sizeof(Node));
	if (NULL == li || n<0) {//分配内存空间失败或元素个数非法
		return ERROR;
	}
	li->next = NULL;//初始头结点指向
	*list = li;//给通过外部链表赋值,指向头结点,此时 list 和 li 都指向头结点。
	for ( i = 0; i < n; i++)
	{
		node = (Node*)malloc(sizeof(Node));//给结点分配空间
		if (NULL == node) {//分配空间失败 
			return ERROR;
		}
		node->data = rand() % 100;//除以100取余的到100以内的数字,不包括100,如果含100 就需要+1
		li->next = node;//新结点 放到链表末尾
		li = node;//移动链表指针指向最新链表最后一个元素,为了下次循环在链表末尾添加元素
		//temp = node;
	}
	//最后表尾元素指针域 设置NULL
	li->next = NULL;
	//*list = li;//一定要放在for循环前面,不然头结点的内存空间没有指向!起初l指向头结点,但是进入for循环后l的指向发生改变要移动指向最新添加的结点元素。
	return OK;
}
//获取链表元素数据,通过指针返回 链表第i个元素的 数据
//i还是按国人的顺序来吧,从1开始
Status getELement(LinkList list, int position,EleType *e) {
	//异常情况:空指针,元素位置非法
	if (NULL == list || position < 1) {
		return ERROR;
	}
	LinkList li = list;
	int i = 1;
	while (li && i<position) {//在链表范围内遍历元素 直到 找到第position位置的 元素  
		i++;
		li = li->next;
	}
	if (NULL == li || position > i) {//超出链表范围,都遍历完链表还没找到元素。
		return ERROR;
	}
	//通上面 while循环 当i = position 跳出循环 ,li 此时指向链表 第position位置的 前面一个结点。
	*e = li->next->data;
	return OK;
}
//往链表中第position位置 插入元素,元素数据为 e
//元素位置从1开始数
Status insertLinkList(LinkList *list,int position,EleType e) {
	Node *node = (Node*)malloc(sizeof(Node));
	//异常情况:空指针,为插入元素分配空间失败,元素位置非法,
	if (NULL == list || NULL==node || position < 1) {
		return ERROR;
	}
	LinkList li = * list;
	int i = 1;
	while ( li && i<position) {//在链表范围内遍历元素 直到 找到第position位置的 元素  
		i++;
		li = li->next;
	}
	if (NULL == li || position > i) {//超出链表范围
		return ERROR;
	}
	//通上面 while循环 当i = position 跳出循环 ,li 此时指向链表 第position位置的 前面一个结点。
	node->data = e;
	node->next = li->next;//让 插入结点指针域指向 原来位置的结点
	li->next = node;//让插入结点位置前的结点 指向插入结点
	return OK;
}
//在链表第position位置 删除元素,通过指针返回 删除元素的数据内容
Status delLinkListEle(LinkList *list, int position, EleType *e) {
	//异常情况:空指针,元素位置非法
	if (NULL == list || position < 1) {
		return ERROR;
	}
	LinkList li = *list;
	Node * node = NULL;
	int i = 1;
	while (li && i<position) {//在链表范围内遍历元素 直到 找到第position位置的 元素  
		i++;
		li = li->next;
	}
	if (NULL == li || position > i) {//超出链表范围,都遍历完链表还没找到元素。
		return ERROR;
	}
	//通上面 while循环 当i = position 跳出循环 ,li 此时指向链表 第position位置的 前面一个结点。
	node = li->next;//保存要删除元素的地址
	li->next = node->next;//让删除元素前置结点 指向 删除元素 直接后继结点。然后就可以释放 删除结点的空间了。
	*e = node->data;//将删除元素数据通过指针修改返回
	free(node);//释放删除元素空间
	return OK;
}
//清空整个链表,释放指针指向的内存
Status freeLinkList(LinkList *list) {
	if (NULL == list)//空指针
		return ERROR;
	//注意:头结点不要释放!只释放头结点后面的结点元素
	//LinkList li = *list;这样将会把头结点也释放掉
	LinkList li = (*list)->next;//将链表指针指向第一个结点元素,从这个元素开始释放
	Node * node = NULL;//临时变量,指向还未释放的元素
	while (li){//链表指针向移动指向结点元素,直到没有后继结点
		node = li->next;//保存要释放结点 的直接后继结点位置。 
		free(li);
		li = node;//继续指向 未释放结点
	}
	//将头结点指针域设置为NULL
	(*list)->next = NULL;
	return OK;
}
int main(void) {

	LinkList linkList;
	EleType e;
	printf("头插法创建链表结构:\n");
	creatLinkListInHead(&linkList, 4);
	printLinkList(&linkList);

	//先释放 然后再用尾插法
	freeLinkList(&linkList);
	printf("尾插法创建链表结构:\n");
	creatLinkListInTail(&linkList, 4);
	printLinkList(&linkList);

	printf("第%d个位置插入%d:\n",5,100);
	//插入元素
	insertLinkList(&linkList, 5, 100);//往链表尾结点后面插入元素
	printLinkList(&linkList);
	printf("第%d个位置插入%d:\n", 3, 103);
	//插入元素
	insertLinkList(&linkList, 3, 103);//链表中间插入元素
	printLinkList(&linkList);
	//获取元素
	getELement(linkList, 4, &e);
	printf("第%d个位置元素:%d\n", 4,e);

	//删除元素
	delLinkListEle(&linkList, 5, &e);
	printf("第%d个位置删除:%d\n", 5, e);
	printLinkList(&linkList);

	
	//删除元素
	delLinkListEle(&linkList, 1, &e);
	printf("第%d个位置删除:%d\n", 1,e);
	printLinkList(&linkList);

	//释放整个表
	freeLinkList(&linkList);
	system("pause");
	return 0;
}






结果验证截图:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值