线性表的链式存储结构
在开始说链式存储之前我们先回顾一下传统的单链表以及链表的发展过程
传统单链表的节点是这样的
typedef struct lnode{
datatype data; //数据域
struct lnode *next; //指针域
}LNode,*LinkedList;
这样有什么样的缺点,我们观察可以发现每个节点分为数据域和指针域两部分,指针域指向的是和它一模一样的节点,用一幅图来展示就是这样:
但是如果是这样的呢?
为了解决这个问题就产生一种新的链表:
其核心思想就是用一些小的节点将我们的大的业务节点串联起来,代码如下:
小节点
typedef struct _tag_LinklistNode
{
struct _tag_LinklistNode *next;
}LinkListNode;
大节点
typedef struct Teacher
{
LinkListNode node;//小节点
int age;
char name[64];
}Teacher;
前言到这里就结束了,下面开始正文!
线性表的顺序存储结构存在许多不便之处,其中尤其体现在插入删除操作中(假如有一亿数据呢),而链式存储由于节点之间在内存中不连续,所以不涉及大量的元素移动。
链式表的基本操作与顺序表类似:创建,插入,删除,求长度,取元素,清空,销毁等等,下面将重点介绍创建,插入。
创建一个线性表
创建时一般会有一个头节点,与首节点不同的是头节点不存数据,这样设计的好处是后续头部插入等操作可以和后面普通位置插入时保持一致。
模型大致如下:
代码如下:
typedef struct _tag_LinklistNode
{
struct _tag_LinklistNode *next;
}LinkListNode; //小节点
typedef struct Teacher
{
LinkListNode node;//小节点
int age;
char name[64];
}Teacher;
typedef struct _tag_LinkList
{
int length;
LinkListNode header;
}TLinkList; //头节点 其中可以保存长度、首节点地址信息。
所以创建一个链式表就是malloc一个头节点,然后后续插入大节点即可形成一条链表。
LinkList* LinkList_Creat()
{
TLinkList *ret = NULL;
ret = (TLinkList *)malloc(sizeof(TLinkList));
memset(ret,0,sizeof(TLinkList));
ret->length = 0;
ret->header.next = NULL;
return ret;
}
接下来说一下链表的插入操作,还是用一幅图来表示:
首先我们设置一个current辅助指针指向header,假如我们要插入1号位置节点。
我们利用一个循环,将current向后跳动至要插入位置的前一个元素:
对应代码如下:
for(i = 0;i<pos;i++)
{
current = current->next;
}
接下来分为三个步骤,打断,新建,新建:
对应代码如下:
node->next = current->next;
current->next = node;
//实际上打断操作在代码中不体现
其他基本操作与顺序表类似,这里不再赘述,直接上完整源码,供大家调试:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
typedef void LinkList;
typedef struct _tag_LinklistNode
{
struct _tag_LinklistNode *next;
}LinkListNode;
typedef struct Teacher
{
LinkListNode node;//小节点
int age;
char name[64];
}Teacher;
//数据域
typedef struct _tag_LinkList
{
int length;
LinkListNode header;
}TLinkList;
LinkList* LinkList_Creat()
{
TLinkList *ret = NULL;
ret = (TLinkList *)malloc(sizeof(TLinkList));
memset(ret,0,sizeof(TLinkList));
ret->length = 0;
ret->header.next = NULL;
return ret;
}
void LinkList_Destory(LinkList* list)
{
if(list != NULL)
{
free(list);
list = NULL;
}
return ;
}
//链表恢复到初始状态
void LinkList_Clear(LinkList* list)
{
TLinkList *tlist = NULL;
if(list == NULL)
{
return ;
}
tlist = (TLinkList *)list;
tlist->length = 0;
tlist->header.next = NULL;
return ;
}
int LinkList_Length(LinkList* list)
{
TLinkList *tlist = NULL;
if(list == NULL)
{
return -1;
}
tlist = (TLinkList *)list;
return tlist->length;
}
//因为链表是单向的,三号位置保存在二号位置的next域中
//指针指向谁,就把谁的地址付给指针
//分清楚链表的操作逻辑和辅助指针变量之间的关系
int LinkList_Insert(LinkList *list,LinkListNode* node,int pos)
{
int i = 0;
int ret = 0;
LinkListNode *current = NULL;
TLinkList * tlist = (TLinkList*)list;
if(list == NULL || node == NULL || pos < 0)
{
ret = -1;
printf("func LinkList_Insert error :%d",ret);
return ret;
}
current = &(tlist->header);
for(i = 0;i<pos;i++)
{
current = current->next;
}
node->next = current->next;
current->next = node;
tlist->length ++;
return 0;
}
LinkListNode* LinkList_Get(LinkList* list,int pos)
{
int i;
int ret = 0;
LinkListNode *current = NULL;
TLinkList * tlist = (TLinkList*)list;
if(list == NULL || pos < 0)
{
ret = -1;
printf("func LinkList_Insert error :%d",ret);
return NULL;
}
current = &(tlist->header);
for(i = 0;i<pos;i++)
{
current = current->next;
}
return current->next;
}
LinkListNode* LinkList_Delete(LinkList* list,int pos)
{
int i;
int tmp = 0;
LinkListNode *current = NULL;
LinkListNode *ret = NULL;
TLinkList * tlist = (TLinkList*)list;
if(list == NULL || pos < 0)
{
tmp = -1;
printf("func LinkList_Insert error :%d",tmp);
return NULL;
}
current = &(tlist->header);
for(i = 0;i<pos;i++)
{
current = current->next;
}
//缓存要删除节点的位置
ret = current->next;
//连线
current->next = ret->next;
tlist->length --;
return ret;
}
int main()
{
LinkList* list = NULL;
int ret,i;
Teacher t1,t2,t3,t4,t5;
t1.age = 31;
t2.age = 32;
t3.age = 33;
t4.age = 34;
t5.age = 35;
list = LinkList_Creat();
ret = LinkList_Insert(list,(LinkListNode *)(&t1),0);
ret = LinkList_Insert(list,(LinkListNode *)(&t2),0);
ret = LinkList_Insert(list,(LinkListNode *)(&t3),0);
ret = LinkList_Insert(list,(LinkListNode *)(&t4),0);
ret = LinkList_Insert(list,(LinkListNode *)(&t5),0);
for(i = 0;i<LinkList_Length(list);i++)
{
Teacher *tmp = (Teacher *)LinkList_Get(list,i);
if(tmp == NULL)
{
return 0;
}
printf("tmp->age:%d\n",tmp->age);
}
printf("length = %d\n",LinkList_Length(list));
for(i = 0;i<4;i++)
{
LinkList_Delete(list,0);
}
for(i = 0;i<LinkList_Length(list);i++)
{
Teacher *tmp = (Teacher *)LinkList_Get(list,i);
if(tmp == NULL)
{
return 0;
}
printf("tmp->age:%d\n",tmp->age);
}
return 0;
}