数据结构 (四) 线性表_企业链表

一. 企业链表概述

① 企业链表简介

企业链表出现的原因:

我们在写传统的链表的时候,节点里面存放的有数据,如果数据的类型固定死了,再我们需要另外一种数据类型的时候,就需要重新写一个链表. 我们也可以使用void*万能指针不固定死数据类型,当然我们还有另外一种实现方式,就是使用企业链表,链表的node里面不存放具体的业务数据类型,这样我们的链表就不受业务数据的限制.

企业链表如何实现

  1. 业务数据分离出来,也就是说链表中的节点只保存指针域.
  2. 你定义的数据一般是一个结构体,要把结构体的第一个位置存放链表中的节点.
  3. 这样你的数据域的地址和链表节点的地址是一样的
  4. 所以你定义的数据的指针,可以当成链表的节点指针来使用.
typedef struct Student
{
	LinkNode node;
	char name[64];
	int age;
} Student;


总结:

  1. 企业级链表的节点,不保存具体的数据域
  2. 业务数据中包含的第一个元素必须是链表的节点类型.
  3. 链表和业务数据的首地址相等

二. 企业链表的实现

  1. 将列表的节点当成业务数据结构体的第一个位置,然后业务数据,在转换之后可以当成节点来使用.
  2. 节点中存放的就是下一个节点的地址

实现的头文件

#ifndef COMPANY_LINK_LIST
#define COMPANY_LINK_LIST
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 链表节点,没有数据域,只保存下一个节点位置
typedef struct LINKNODE
{
	struct LINKNODE *next;
} LinkNode;

// 链表结构体,存放节点和大小
typedef struct 
{
	LinkNode head; // 存放的是结构体
	int size;
} LinkList;

// 声明打印的函数指针
typedef void (*PRINT_PTR)(LinkNode *);

// 比较函数指针
typedef int (*COMPARE_PTR)(LinkNode *, LinkNode *);

// 初始化链表
LinkList *init_linklist();

// 插入
void insert_linklist(LinkList *list, int pos, LinkNode *data);

// 删除根据位置去删除
void remove_linklist(LinkList *list, int pos);

// 查找
int find_linklist(LinkList *list, LinkNode *data, COMPARE_PTR compare);

// 链表大小
int get_size_linklist(LinkList *list);

// 清空数据 链表依然可以使用
void clear_linklist(LinkList *list);

// 销毁链表
void free_space_linklist(LinkList *list);

// 打印
void print_linklist(LinkList *list, PRINT_PTR print);



#endif // !COMPANY_LINK_LIST

具体实现

#include "CompanyLinkList.h"
// 初始化链表
LinkList *init_linklist()
{
	// 为链表本身分配内存
	LinkList *list = (LinkList *)malloc(sizeof(LinkList));
	if (list != NULL)
	{
		list->head.next = NULL; // 下一个元素指向NULL
		list->size = 0;
		return list;
	}
	return NULL;
}

// 插入
void insert_linklist(LinkList *list, int pos, LinkNode *data)
{
	if (pos <0 || pos > list->size)
	{
		pos = list->size;
	}
	// 插入操作,先遍历,然后插入
	if (list != NULL && data != NULL)
	{
		// 找到插入位置的前驱结点
		LinkNode* pre = &(list->head);
		for (int i = 0; i < pos; i++)
		{
			pre = pre->next;
		}
		// 插入新节点,当新节点指向pos位置
		data->next = pre->next;
		// 将pos位置的前驱节点指向新节点
		pre->next = data;

		list->size++;
		
	}
}

// 删除根据位置去删除
void remove_linklist(LinkList *list, int pos)
{
	if (pos < 0 || pos >= list->size)
	{
		return;
	}
	if (list != NULL)
	{
		LinkNode *pCurrent = &(list->head);
		for (int i = 0; i < pos; i++)
		{
			pCurrent = pCurrent->next; // 找到当前下标的指针
		}
		// pCurrent 是pos位置的前驱节点,将pos位置的指针删除掉,就相当于是
		// pos的前驱节点指向pos的下一个节点,因为不是自己开辟的内存,不需要释放内存
		pCurrent->next = pCurrent->next->next;
		list->size--;
	}
	return;
}

// 查找
int find_linklist(LinkList *list, LinkNode *data, COMPARE_PTR compare)
{
	if (list != NULL && data != NULL)
	{
		LinkNode *pCurrent = list->head.next; // 第一个节点(头节点的下一个)
		int index = 0;
		int indexFinded = -1;
		while (pCurrent != NULL)
		{
			if (compare(data, pCurrent) == 0)
			{
				indexFinded = index;
				break;
			}
			pCurrent = pCurrent->next;
			index++;
		}
		return indexFinded;
	}
}

// 链表大小
int get_size_linklist(LinkList *list)
{
	if (list != NULL)
	{
		return list->size;
	}
	return -1;
}

// 清空数据 链表依然可以使用
void clear_linklist(LinkList *list)
{
	if (list != NULL)
	{
		list->head.next = NULL;
		list->size = 0;
	}
	return;
}

// 销毁链表
void free_space_linklist(LinkList *list)
{
	if (list == NULL)
	{
		return;
	}
	free(list);
}

// 打印
void print_linklist(LinkList *list, PRINT_PTR print)
{
	if (list != NULL)
	{
		// 辅助指针
		LinkNode *pCurrent = list->head.next;
		while (pCurrent != NULL)
		{
			print(pCurrent);
			pCurrent = pCurrent->next;
		}
	}
	return;
}

测试代码:

#include "CompanyLinkList.h"

// 业务数据中保存的是节点信息.
// 第一个是节点类型
// 节点里面存放的是下一个节点的地址.
typedef struct Person
{
	LinkNode node;
	char name[64];
	int age;
} Person;

void my_print(LinkNode *data)
{
	Person * p = (Person *)data;
	printf("Name:%s, Age:%d\n",p->name,p->age);
}

int my_compare(LinkNode *node1, LinkNode *node2)
{
	Person* p1 = (Person *)node1;
	Person* p2 = (Person *)node2;
	if (strcmp(p1->name, p2->name) == 0 && p1->age == p2->age)
	{
		return 0;
	}
	return -1;
}

int main()
{
	LinkList *list = init_linklist();
	// 创建数据
	Person p1, p2, p3, p4, p5;
	int charLen = sizeof(p1.name) / sizeof(p1.name[0]);
	strcpy_s(p1.name, charLen, "aaaa");
	strcpy_s(p2.name, charLen, "bbbb");
	strcpy_s(p3.name, charLen, "cccc");
	strcpy_s(p4.name, charLen, "dddd");
	strcpy_s(p5.name, charLen, "eeee");

	p1.age = 10;
	p2.age = 20;
	p3.age = 30;
	p4.age = 40;
	p5.age = 50;

	insert_linklist(list, 0, (LinkNode *)&p1);
	insert_linklist(list, 0, (LinkNode *)&p2);
	insert_linklist(list, 0, (LinkNode *)&p3);
	insert_linklist(list, 0, (LinkNode *)&p4);
	insert_linklist(list, 0, (LinkNode *)&p5);

	// 打印
	print_linklist(list, my_print);

	printf("_________________________________\n");

	// 删除3位置的元素
	remove_linklist(list, 3);
	print_linklist(list, my_print);

	// 查找一个数据是否存在
	Person newP1;
	strcpy_s(newP1.name, charLen, "aaaa");
	newP1.age = 10;

	int pos = find_linklist(list, (LinkNode *) &newP1, my_compare);
	if (pos == -1)
	{
		printf("未找到!\n");
	}
	else
	{
		printf("找到了,位置: %d\n", pos);
	}
	newP1.age = 20;
	pos = find_linklist(list, (LinkNode *)&newP1, my_compare);
	if (pos == -1)
	{
		printf("未找到!\n");
	}
	else
	{
		printf("找到了,位置: %d\n", pos);
	}

	// 链表的大小
	printf("链表大小为: %d\n", get_size_linklist(list));

	// 清空链表
	clear_linklist(list);
	printf("清空后,链表大小: %d\n", get_size_linklist(list));

	system("pause");
	return 0;
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值