c语言实现企业链表
我们最早学习的线性表分为顺序表和链表,顺序表即用数组来模拟链表,他的内存是连续的;缺点在于事先要知道大小,但是实际生活中我们并不能实现准确的预知对象有多大,需要多少内存。因此就诞生了链式存储的顺序表,即链表;链表也是分为三种,传统链表、内核链表,和企业链表。那么这三种链表分别有什么特点呢?
(1)传统链表:传统链表区别于数组模拟的线性表,可以不用管到底需要多大的内存,比较方便。第二个特点是他的内存不是连续的,每个结点包含一个数据域和指针域。每个节点的指针域保存的是下一个节点的地址。他的缺点在于,如果节点的成员变量发生改变(新增或者删除)那么整个程序都要随之改变。
(2)内核链表:内核链表全名为linux内核链表,由linux之父linus(托瓦尔兹)发明。发明这个链表的原因是基于以上的问题,传统链表不能包含世间万物,那索性他就不包含了,反过来让世间万物包含我,是不是很有哲学思想。他的缺点在于,指针节点在结构体内有一个地址偏移量。
(3)企业链表:基于上面的问题,内核链表的指针成员变量有一个偏移量,那么企业链表的改变在于,将指针成员变量前移至第一个成员变量,这样整个结构体的内存地址和第一个成员变量(即指针成员变量)就重合了,解决了地址偏移量的 问题;他们的技术推演路线图如下:
我们平时用的就是传统链表和企业链表。下面我们来看这两种链表用C/C++的实现方式:
//传统链表
// 数据结构.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
using namespace std;
typedef struct node
{
int data;
node* next;
}Slist;
Slist* creatlist();
int printSlist(Slist* phead);
int delnode(Slist*, int x);
int insertnode(Slist*, int x, int y);
int destroynode(Slist*);
int main()
{
//Slist* phead, * PM, Pcur;
Slist* phead;
phead=creatlist();
cout << " " << endl;
printSlist(phead);
insertnode(phead, 20, 19);
printSlist(phead);
delnode(phead, 19);
printSlist(phead);
destroynode(phead);
printSlist(phead);
std::cout << "Hello World!\n";
}
Slist* creatlist()
{
int x;
Slist* Phead, *PM, *Pcur;
Phead = (Slist*)malloc(sizeof(Slist));
if (Phead == NULL)
{
return NULL;
}
else
{
Phead->data = 0;
Phead->next = NULL;
}
cout << "please inter your data" << endl;
cin >> x;
Pcur = Phead;
while (x!= -1)
{
PM = (Slist*)malloc(sizeof(Slist));
if (PM == NULL)
{
return NULL;
}
else
{
PM->data = x;
PM->next = NULL;
Pcur->next = PM;
Pcur = PM;
cin >> x;
}
}
return Phead;
}
int printSlist(Slist* phead)
{
Slist* tmp;
if (phead == NULL)
{
return -1;
}
tmp = phead->next;
while (tmp)
{
cout << tmp->data<<" ";
tmp = tmp->next;
}
return 0;
}
//单项链表的位置保存在前驱节点的next中
int insertnode(Slist* Phead, int x, int y)
{
Slist * pPre, * pM, * pCur;
pM = (Slist*)malloc(sizeof(Slist));
if (pM == NULL)
return -1;
pPre = Phead;
pCur = pPre-> next;
while (pCur)
{
if (pCur->data == x)
{
pM->data = y;
pM->next = pCur;
pPre->next = pM;
}
pPre = pCur;
pCur = pCur->next;
}
return 0;
}
int delnode(Slist* phead, int x)
{
Slist* pPre, *pCur;
pPre = phead;
pCur = phead->next;
while (pCur)
{
if (pCur->data == x)
{
//pPre->next = pCur->next;
//free(pCur);释放内存之后得到不能再用pCur;所以pPre可能是一个野指针;导致程序崩溃;
break;
}
pPre = pCur;
pCur = pCur->next;
}
if (pCur == NULL)
{
cout << "没找到节点" << endl;
return -1;
}
pPre->next = pCur->next;
free(pCur);
return 0;
}
int destroynode(Slist* phead)
{
Slist* tmp = NULL;
if (phead == NULL)
return -1;
while(phead)
{
tmp = phead->next;
free(phead);
phead = tmp;
}
return 0;
}
//上面部分是传统链表的一些基本操作;下面我们来看企业链表的一些api函数;
//企业链表,企业链表我们将业务结点和算法分开实现;
//定义一个企业链表的头文件,将结点的定义和api函数的实现全部包含进来
//LinK_List.h
#ifndef _MYLINKLIST_H_
#define _MYLINKLIST_H_
typedef void LinkList;
typedef struct _tag_LinkListNode
{
struct _tag_LinkListNode* next;
}LinkListNode;//定义一个结点,后面讲这个结点包含进去业务节点,然后将这个结点连起来,所有的业务结点就自然而然的连起来了;
LinkList* LinkList_Creat();
void LinkList_Destroy(LinkList* list);
void LinkList_Clear(LinkList* list);
int LinkList_Length(LinkList* list);
int LinkList_Insert(LinkList* list, LinkListNode* node, int pos);
LinkListNode* LinkList_Get(LinkList* list, int pos);
LinkListNode* LinkList_Delete(LinkList* list, int pos);
#endif
//链表及其基本api函数的底层实现
//Link_List.cpp
#include<iostream>
#include"LinkList.h"
using namespace std;
typedef struct _tag_LinkList
{
LinkListNode header;
int length;
}TLinkList;
LinkList* LinkList_Creat()
{
TLinkList* tmp = NULL;
tmp = (TLinkList*)malloc(sizeof(TLinkList));
if (tmp == NULL)
{
cout << "LinkList_Create() error" << endl;
return NULL;
}
memset(tmp, 0, sizeof(TLinkList));
return tmp;
}
void LinkList_Destroy(LinkList* list)
{
if (list == NULL)
{
return;
}
free(list);
return;
}
void LinkList_Clear(LinkList* list)
{
TLinkList* tlist = NULL;
tlist = (TLinkList*)list;
if (tlist == NULL)
{
return;
}
tlist->header.next = NULL;
tlist->length = 0;
return;
}
int LinkList_Length(LinkList* list)
{
TLinkList* tlist = NULL;
tlist = (TLinkList*)list;
if (tlist == NULL)
{
return -1;
}
return tlist->length;
}
int LinkList_Insert(LinkList* list, LinkListNode* node, int pos)
{
int i = 0;
LinkListNode *pcur=NULL;
TLinkList* tList = NULL;
tList = (TLinkList*)list;
pcur = &(tList->header);
if (list == NULL || node == NULL || pos < 0)
{
return -1;
}
for (i = 0; i < pos; i++)
{
pcur = pcur->next;
}
node->next = pcur->next;
pcur->next = node;
tList->length++;
return 0;
}
LinkListNode* LinkList_Get(LinkList* list, int pos)
{
int i = 0;
LinkListNode* pcur = NULL;
TLinkList* tList = NULL;
tList = (TLinkList*)list;
pcur = &(tList->header);
if (list == NULL || pos < 0)
{
return NULL;
}
for (i = 0; i < pos; i++)
{
pcur = pcur->next;
}
return pcur->next;
}
LinkListNode* LinkList_Delete(LinkList* list, int pos)
{
int i = 0;
LinkListNode* pcur = NULL;
LinkListNode* ret = NULL;
TLinkList* tlist=NULL;
tlist = (TLinkList*)list;
pcur = &(tlist->header);
if (list == NULL || pos < 0)
{
return NULL;
}
for (i = 0; i < pos; i++)
{
pcur = pcur->next;
}
ret=pcur->next;
pcur->next = ret->next;
tlist->length--;
//free(ret);
return ret;
}
//上层测试函数
//链表框架搭建及实现.cpp
#include<iostream>
#include"LinkList.h"
using namespace std;
//思考1:业务节点和链表算法是如何分离的
//思考2:业务节点的生命周期归测试程序管;
typedef struct _Teacher//业务节点
{
LinkListNode node;
char name[32];
int age;
}Teacher;
void main()
{
Teacher t1, t2, t3,t4,t5,t6;
t1.age = 31;
t2.age = 32;
t3.age = 33;
t4.age = 34;
t5.age = 35;
t6.age = 36;
LinkList* list = NULL;
list = LinkList_Creat();
//插入元素
LinkList_Insert(list, (LinkListNode*)(&t1), 0);
LinkList_Insert(list, (LinkListNode*)(&t2), 0);
LinkList_Insert(list, (LinkListNode*)(&t3), 0);
LinkList_Insert(list, (LinkListNode*)(&t4), 0);
LinkList_Insert(list, (LinkListNode*)(&t5), 0);
LinkList_Insert(list, (LinkListNode*)(&t6), 3);
//遍历链表
for (int i = 0; i<LinkList_Length(list); i++)
{
Teacher* tmp = (Teacher*)LinkList_Get(list, i);
if (tmp == NULL)
return;
cout << tmp->age << endl;
}
//删除链表;
while (LinkList_Length(list) > 0)
{
Teacher* tmp = (Teacher*)LinkList_Delete(list, 0);
if (tmp == NULL)
return;
cout << tmp->age << endl;
}
LinkList_Destroy(list);
return ;
}