线性表的链式存储设计与实现
1.概念
(1)为了存储每个数据元素和其直接后继元素之间的逻辑关系,每个元素除了存储本身的信息之外,还需存储只是其直接后继的信息。n个结点链接成一个链表,每个结点只包含一个指针域,又叫单链表。
(2)单链表正是通过每个结点的指针域将线性表的数据元素按其逻辑次序链接在一起。
(3)表头结点:链表中的第一个结点,包含指向第一个数据元素的指针和链表自身的一些信息。
(4)数据结点:链表中代表数据元素的结点,包含指向下一个数据元素的指针和数据元素的信息。
(5)尾结点:链表中最后一个结点,其下一个指针为空,表示无后继。
2.实现过程
(1)linklist.h
#ifndef _MYLINKLIST_H_ #define _MYLINKLIST_H_ typedef void LinkList; typedef struct _tag_LinkListNode { struct _tag_LinkListNode* next; }LinkListNode; LinkList* LinkList_Create(); void LinkList_Destory(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 _MYLINKLIST_H_
(2)linklist.c
#include <stdlib.h> #include <stdio.h> #include <string.h> #include "linklist.h" typedef void LinkList; typedef struct _tag_LinkList { LinkListNode header; int length; }TLinkList; LinkList* LinkList_Create() { 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; } int LinkList_Insert(LinkList* list, LinkListNode* node, int pos) { int ret = 0; TLinkList* tList = NULL; LinkListNode* Current = NULL; if (list == NULL) { ret = -1; printf("func LinkList_Insert() err:%d\n", ret); return ret; } tList = (TLinkList*)list; Current = &(tList->header); for (int i = 0; i < pos && (Current->next != NULL); i++) { Current = Current->next; } //1 让node连接后续结点 node->next = Current->next; //2 让node连接前面的链表 Current->next = node; tList->length++; return 0; } LinkListNode* LinkList_Get(LinkList* list, int pos) { int ret = 0; TLinkList* tList = NULL; LinkListNode* Current = NULL; if (list == NULL || pos < 0) { ret = -1; printf("func LinkList_Get() err:%d\n", ret); return NULL; } tList = (TLinkList*)list; Current = &(tList->header); for (int i = 0; i < pos && (Current->next != NULL); i++) { Current = Current->next; } return Current->next; } LinkListNode* LinkList_Delete(LinkList* list, int pos) { TLinkList* tList = NULL; LinkListNode* Current = NULL; LinkListNode* ret = NULL; if (list == NULL || pos < 0) { printf("func LinkList_Get() err!\n"); return NULL; } tList = (TLinkList*)list; Current = &(tList->header); for (int i = 0; i < pos && (Current->next != NULL); i++) { Current = Current->next; } //1 缓存被删除的结点位置 ret = Current->next; //2 链接后面的结点 Current->next = ret->next; tList->length--; return ret; }
(3)demo.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h> #include "linklist.h" typedef struct Teacher { LinkListNode node; int age; char name[64]; }Teacher; void maindm005() { int ret = 0; int len = 0; int i = 0; Teacher t1, t2, t3, t4, t5; t1.age = 31; t2.age = 32; t3.age = 33; t4.age = 34; t5.age = 35; //创建线性表 LinkList* list = NULL; list = LinkList_Create(); if (list == NULL) { ret = -1; printf("func LinkList_Create() err:%d\n", ret); return ; } //插入值 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); len = LinkList_Length(list); //遍历 for (i = 0; i < len; i++) { Teacher *tmp = (Teacher *)LinkList_Get(list, 0); if (tmp == NULL) { return; } printf("tmp->age:%d ", tmp->age); } printf("\n"); //删除元素 while (len > 0) { Teacher *tmp = (Teacher *)LinkList_Delete(list, 0); if (tmp == NULL) { return; } printf("tmp->age:%d ", tmp->age); } printf("\n"); LinkList_Destory(list); system("pause"); return; }
3.优缺点
(1)优点
无需一次性控制链表的容量;插入和删除操作无需一定数据元素。
(2)缺点
数据元素必须保存后级元素的位置信息;获取指定数据的元素操作需要顺序访问之前的元素。