接上篇:C++数据结构X篇_04_单向链表框架搭建、实现和测试(链表的定义,常用操作的实现等),比较好的博文参考:C++实现企业链表,本篇基本就是按照该博文进行的整理,视频中介绍的是利用C实现的方法,繁杂且当前我并未完全实现。
文章目录
1. 企业链表
企业链表是企业中经常使用的一种链表,因此被称为企业链表。企业链表是企业中经常使用的一种链表,因此被称为企业链表。我们首先来看看他的结构与传统链表有啥不同:
对于一个类或结构体 ,其中包含我们需要存储的数据data与一个指针变量p_next,我们将p_next串起来便形成了企业链表,那它和普通链表有何区别呢?普通链表中p_next指向的是下一个p_next与data组成的类或结构体整体的地址,而企业链表p_next仅仅指向下一个p_next的地址。
因此链表中并未涉及任何data数据,企业链表实际存储的数据结构为:
理论说完了,那如何实现呢?
1.1 首先应定义节点与链表并对其初始化
//链表指针节点节点
class node_p
{
public:
node_p* next;
};
//链表
class list
{
public:
//当给list分配内存时,head内存也会同时分配,释放时只需要释放list即可
node_p head;
int size;
};
//初始化链表
list * list_init()
{
list* L=new list;
L->head.next=NULL;
L->size=0;
return L;
}
1.2 再确定链表的插入删除函数
/插入
void list_insert(list* L,int pos,node_p* data)
{
//查找位置
node_p* pcurrent=&(L->head);
for (int i = 0; i < pos; i++)
{
pcurrent=pcurrent->next;
}
//插入新的指针节点
data->next=pcurrent->next;
pcurrent->next=data;
L->size++;
}
//删除
void list_delete(list* L,int pos)
{
//查找位置
node_p* pcurrent=&(L->head);
for (int i = 0; i < pos-1; i++)
{
pcurrent=pcurrent->next;
}
//删除节点
pcurrent->next=pcurrent->next->next;
L->size--;
}
到这里除了node的定义中未放入data外,其余操作与普通链表一致。那么企业链表是如何放入数据的呢?
1.3 我们先自定义一个数据节点:
//自定义链表数据节点
class my_data
{
public:
node_p p_data; //定义为node_p* p_data效果也是一样,后期考虑为什么node_p* next;与此等效
int num;
};
当我们创建my_data的对象指针p1,将其强转成node_p的对象指针a1,a1->next=p1->p_data(具体原理见C++57个入门知识点_番外1_C++指针偏移在类中的应用及指针偏移原理)。因此p1可以通过a1被插入企业链表中,当需要使用p1->num时,只需要再将a1强转成my_data的对象指针即可正常访问。
1.4 下面提供根据自定义数据提供打印函数:
void my_print(node_p* data)
{
my_data* p=(my_data*)data;
cout<<p->num<<"\t";
}
//打印链表
void list_print(list* L)
{
node_p* pcurrent=L->head.next;
while (pcurrent != NULL)
{
my_print(pcurrent);
pcurrent=pcurrent->next;
}
cout<<endl;
}
1.5 实验与结果
int main()
{
//创建链表
list* L=list_init();
//创建数据
my_data data[9];
for (int i = 0; i < 10; i++)
{
data[i].num=i+1;
}
//插入数据1~10
for (int i = 0; i < 10; i++)
{
list_insert(L,i,(node_p*)&data[i]); //把节点串起来
}
//打印数据
cout<<"链表中数据为:"<<endl;
list_print(L);
//删除pos=5的数据(跳过head)
list_delete(L,5);
cout<<"删除pos=5后:"<<endl;
list_print(L);
system("pause");
return 0;
}
1.6 整体代码
#include <iostream>
using namespace std;
//链表指针节点节点
class node_p
{
public:
node_p* next;
};
//链表
class list
{
public:
//当给list分配内存时,head内存也会同时分配,释放时只需要释放list即可
node_p head;
int size;
};
//自定义链表数据节点
class my_data
{
public:
node_p p_data;
int num;
};
//初始化链表
list * list_init()
{
list* L = new list;
L->head.next = NULL;
L->size = 0;
return L;
}
// 插入
void list_insert(list* L, int pos, node_p* data)
{
//查找位置
node_p* pcurrent = &(L->head);
for (int i = 0; i < pos; i++)
{
pcurrent = pcurrent->next;
}
//插入新的指针节点
data->next = pcurrent->next;
pcurrent->next = data;
L->size++;
}
//删除
void list_delete(list* L, int pos)
{
//查找位置
node_p* pcurrent = &(L->head);
for (int i = 0; i < pos - 1; i++)
{
pcurrent = pcurrent->next;
}
//删除节点
pcurrent->next = pcurrent->next->next;
L->size--;
}
void my_print(node_p* data)
{
my_data* p = (my_data*)data;
cout << p->num << "\t";
}
//打印链表
void list_print(list* L)
{
node_p* pcurrent = L->head.next;
while (pcurrent != NULL)
{
my_print(pcurrent);
pcurrent = pcurrent->next;
}
cout << endl;
}
int main()
{
//创建链表
list* L = list_init();
//创建数据
my_data data[9];
for (int i = 0; i < 10; i++)
{
data[i].num = i + 1;
}
//插入数据1~10
for (int i = 0; i < 10; i++)
{
list_insert(L, i, (node_p*)&data[i]); //把节点串起来
}
//打印数据
cout << "链表中数据为:" << endl;
list_print(L);
//删除pos=5的数据(跳过head)
list_delete(L, 5);
cout << "删除pos=5后:" << endl;
list_print(L);
system("pause");
return 0;
}
1.7 C的实现方法(并未完全实现,后期有时间了再进行补充,作参考)
1.7.1 LinkList.h
#pragma once
#ifndef LINKLIST_H
#define LINKLIST_H
//链表小节点
typedef struct LINKNODE {
struct LINKNODE* next;
}LinkNode;
//链表节点
typedef struct LINKLIST {
LinkNode head;
int size;
}LinkList;
//遍历函数指针
typedef void(*PRINTNODE)(LinkNode*);
//比较函数指针
typedef int(*COMPARENODE)(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, COMPARENODE compare);
//返回链表大小
int Size_LinkList(LinkList* list);
//打印
void Print_LinkList(LinkList* list, PRINTNODE print);
//释放链表内存
void FreeSpace_LinkList(LinkList* list);
#endif
1.7.2 LinkList.cpp
#include<iostream>
#include "LinkList.h"
//初始化链表
LinkList* Init_LinkList() {
LinkList* list = (LinkList*)malloc(sizeof(LinkList));
list->head.next = nullptr;
list->size = 0;
return list;
}
//插入
void Insert_LinkList(LinkList* list, int pos, LinkNode* data) {
if (list == nullptr) {
return;
}
if (data == nullptr) {
return;
}
if (pos<0||pos>list->size) {
pos = list->size;
}
//查找插入位置
LinkNode* pCurrent = &(list->head);
for (int i = 0; i < pos; i++) {
pCurrent = pCurrent->next;
}
//插入新节点
data->next = pCurrent->next;
pCurrent->next = data;
list->size++;
}
//删除
void Remove_LinkList(LinkList* list, int pos) {
if (list == nullptr) {
return;
}
if (pos<0 || pos>list->size) {
return;
}
//辅助指针变量
LinkNode* pCurrent = &(list->head);
for (int i = 0; i < pos; i++) {
pCurrent = pCurrent->next;
}
//删除节点
pCurrent->next = pCurrent->next->next;
list->size--;
}
//查找
int Find_LinkList(LinkList* list, LinkNode* data, COMPARENODE compare) {
if (list == nullptr) {
return;
}
if (data == nullptr) {
return;
}
//辅助指针变量
LinkNode* pCurrent = list->head.next;
int index = 0;
while (pCurrent != nullptr) {
if (compare(pCurrent, data) == 0) {
break;
}
pCurrent = pCurrent->next;
index++;
}
return index;
}
//返回链表大小
int Size_LinkList(LinkList* list) {
return 0;
}
//打印
void Print_LinkList(LinkList* list, PRINTNODE print) {
if (list == nullptr) {
return;
}
//辅助指针
LinkNode* pCurrent = list->head.next;
while (pCurrent != nullptr) {
print(pCurrent);
pCurrent = pCurrent->next;
}
}
//释放链表内存
void FreeSpace_LinkList(LinkList* list) {
if (list == nullptr) {
return;
}
free(list);
}
1.7.3 ListTest3.cpp
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include "LinkList.h"
#define _CRT_SECURE_NO_WARNINGS
typedef struct PERSON {
LinkNode node;
char name[64];
int age;
}Person;
void MyPrint(LinkNode* data) {
Person* p = (Person*)data;
printf("Name:%s Age:%d\n",p->name,p->age);
}
int main()
{
//创建链表
LinkList* list = Init_LinkList();
//创建数据
Person p1, p2, p3, p4, p5;
strcpy_s(p1.name, "aaa");
strcpy_s(p2.name, "bbb");
strcpy_s(p3.name, "ccc");
strcpy_s(p4.name, "ddd");
strcpy_s(p5.name, "eee");
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, MyPrint);
//释放链表内存
FreeSpace_LinkList(list);
}
2. linux内核链表
上面介绍的企业链表p_next是第一个成员变量,而linux内核链表中p_next是最后一个成员变量,这样与首地址存在一个偏移量才能找到LINKNODE* next
的问题,企业链表也可以看做是linux内核链表的改进版。具体示意图如下所示
3. 学习视频地址:
企业链表思路;企业链表实现_测试1;企业链表实现_测试2