线性表的链式存储
1、基本概念
链式存储定义
为了表示每个数据元素与其直接后继元素之间的逻辑关系,每个元素除了存储本身的信息外,还需要存储指示其直接后继的信息。
表头结点
链表中的第一个结点,包含指向第一个数据元素的指针以及链表自身的一些信息
数据结点
链表中代表数据元素的结点,包含指向下一个数据元素的指针和数据元素的信息
尾结点
链表中的最后一个数据结点,其下一元素指针为空,表示无后继。
2、设计与实现
在C语言中可以用结构体来定义链表中的指针域,链表中的表头结点也可以用结构体实现
带头结点、位置从0的单链表
返回链表中第3个位置处,元素的值
LinkListNode* LinkList_Get(LinkList* list, int pos)
{
int i = 0;
TLinkList *tList = (TLinkList *)list;
LinkListNode *current = NULL;
LinkListNode *ret = NULL;
if (list==NULL ||pos<0 || pos>=tList->length)
{
return NULL;
}
current = (LinkListNode *)tList;
for (i=0; i<pos; i++)
{
current = current->next;
}
ret = current->next;
return ret ;
}
返回第三个位置的
移动pos次以后,当前指针指向哪里?
答案:指向位置2,所以需要返回 ret = current->next;
备注:
循环遍历时, 遍历第1次,指向位置0
遍历第2次,指向位置1
遍历第3次,指向位置2
遍历第n次,指向位置n-1;
所以如果想返回位置n的元素的值,需要怎么做
ret = current->next;
此问题是:指向头结点的指针移动n次 和 第n个元素之间的关系?
删除元素
3、优点和缺点
优点:
无需一次性定制链表的容量
插入和删除操作无需移动数据元素
缺点:
数据元素必须保存后继元素的位置信息
获取指定数据的元素操作需要顺序访问之前的元素
程序演示:(此程序实现算法与程序类型分离)
头文件
#ifndef _zeng_
#define _zeng_
typedef void LinkList;
//注意该结构体地址等于&next地址
typedef struct xiaozeng
{
struct xiaozeng*next;
}LinkListNode;//结点
//创建头结点
LinkList *LinkList_Create();
//销毁链表
void LinkList_Destroy(LinkList *list);
//链表清空
void LinkList_Clear(LinkList *list);
//获取链表长度
int LinkList_Length(LinkList *list);
//插入结点地址
void LinkList_Insert(LinkList *list, LinkListNode *node, int pos);
//得到结点地址
LinkListNode *LinkList_Get(LinkList *list, int pos);
//得到删除结点地址
LinkListNode *LinkList_Delete(LinkList *list, int pos);
#endif
实现.c
#include"1.h"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct _zzzz
{
LinkListNode header;//指向下一个结点
int length;//保存链表长度
}TLinkList;
//创建链表
LinkList *LinkList_Create()
{
TLinkList *ret = (TLinkList*)malloc(sizeof(TLinkList));
memset(ret, 0, sizeof(TLinkList));//初始化内存
if (ret == NULL)
{
printf("创建头结点失败\n");
return NULL;
}
ret->length = 0;//初始化为空
ret->header.next = NULL;
return ret;//返回头结点地址
}
//销毁结点
void LinkList_Destroy(LinkList *list)
{
TLinkList *tmp = (TLinkList*)list;//类型转换
if (tmp == NULL)
{
printf("链表为空\n");
return;
}
free(tmp);//释放内存
}
//链表清空
void LinkList_Clear(LinkList *list)
{
TLinkList *tmp = (TLinkList*)list;
if (tmp == NULL)
{
printf("链表为空\n");
return;
}
tmp->length = 0;//长度置0
tmp->header.next = NULL;
return;
}
//获取链表长度
int LinkList_Length(LinkList *list)
{
TLinkList *tmp = (TLinkList*)list;
if (tmp == NULL)
{
printf("链表为空\n");
return -1;
}
return tmp->length;//返回长度
}
//插入结点 //表头 //插入结点 //位置,从0号开始
void LinkList_Insert(LinkList *list, LinkListNode *node, int pos)
{
TLinkList *tmp = (TLinkList*)list;
//注意该结构体地址等于&next地址
LinkListNode *current = &tmp->header.next;//指向头结点
if (list == NULL || node == NULL || pos < 0)
{
printf("插入失败\n");
return;
}
//容错性,使得不断为空
if (pos>LinkList_Length(list))
{
pos = LinkList_Length(list);
}
for (int i = 0; i < pos && (current->next != NULL); i++)
{
current = current->next;
}
//现在current指向pos前一个结点
node->next = current->next; //先将前一个结点保存的地址赋值给node->next
current->next = node; //再将node地址赋给current->next;两步实现插入
tmp->length++; //插入后长度+1
return;
}
//获得指定位置结点地址
LinkListNode *LinkList_Get(LinkList *list, int pos)
{
TLinkList *tmp = (TLinkList*)list;
LinkListNode *current = &tmp->header.next;//从头开始
if (list == NULL || pos < 0||pos>=LinkList_Length(list))
{
printf("获取失败\n");
return NULL;
}
for (int i = 0; i < pos && (current->next != NULL); i++)
{
current = current->next;
}
//现在current指向pos前一个结点
return current->next;
}
//删除一个结点并返回该删除结点地址
LinkListNode *LinkList_Delete(LinkList *list, int pos)
{
TLinkList *tmp = (TLinkList*)list;
LinkListNode *current = &tmp->header.next;
if (list == NULL || pos < 0 || pos >= LinkList_Length(list))
{
printf("删除失败\n");
return NULL;
}
for (int i = 0; i < pos && (current->next != NULL); i++)
{
current = current->next;
}
LinkListNode *bao = current->next;//缓冲保存
current->next = current->next->next;//删除该结点,就是把指向该结点变成指向该结点指向的结点
tmp->length--;//长度-1
return bao;//返回其结点
}
主函数
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include"1.h"
typedef struct Teacher //即将被插入结点
{
int data;//将被当做指针用,存储地址,只要是4个字节就OK,可以定义为LinkListnode Node//4个字节
char name[4];
int age;
}Teacher;
int main()
{
Teacher t1, t2, t3;
int length, i = 0;
t1.age = 31;
t2.age = 32;
t3.age = 33;
LinkList *list = LinkList_Create();
//强制转换使得t1的4个字节当做指针用
LinkList_Insert(list, (LinkListNode *)&t1, LinkList_Length(list));
LinkList_Insert(list, (LinkListNode *)&t2, LinkList_Length(list));
LinkList_Insert(list, (LinkListNode *)&t3, LinkList_Length(list));
for (i = 0; i < LinkList_Length(list); i++)
{
Teacher *tmp=(Teacher*)LinkList_Get(list, i);
if (tmp != NULL)
{
printf("age:%d ", tmp->age);
}
}
while (LinkList_Length(list)>0)
{
Teacher *tmp = (Teacher*)LinkList_Delete(list, 0);
if (tmp!= NULL)
{
printf("age: %d ", tmp->age);
}
}
LinkList_Destroy(list);
system("pause");
}