链表的基本概念:
1、表头结点
链表中的第一个结点,包含指向第一个数据元素的指针以及链表自身的一些信息
2、数据结点
链表中代表数据元素的结点,包含指向下一个数据元素的指针和数据元素的信息
3、尾结点
链表中最后一个数据结点,其下一个元素指针为空,表示无后继
LinkList.c
#include <malloc.h> #include <stdio.h> #include "LinkList.h" typedef struct _tag_LinkList { LinkListNode header; int length; }TLinkList; LinkList* LinkList_Create() { TLinkList* ret = (TLinkList*)malloc(sizeof(TLinkList)); if(ret != NULL) { ret->length = 0; ret->header.next = NULL; } return ret; } void LinkList_Destroy(LinkList* list) { free(list); } void LinkList_Clear(LinkList* list) { TLinkList* sList = (TLinkList*)list; if(sList != NULL) { sList->length = 0; sList->header.next = NULL; } } int LinkList_Length(LinkList* list) { TLinkList* sList = (TLinkList*)list; int ret = -1; if(sList != NULL) { ret = sList->length; } return ret; } int LinkList_Insert(LinkList* list, LinkListNode* node, int pos) { TLinkList* sList = (TLinkList*)list; int ret = (sList != NULL)&&(pos >=0)&&(node != NULL); int i=0; if(ret) { LinkListNode* current = (LinkListNode*)sList; //让current指向头结点 for(i=0;(i<pos)&&(current->next != NULL); i++) { current = current->next; } node->next = current->next; current->next = node; sList->length++; } return ret; } LinkListNode* LinkList_Get(LinkList* list, int pos) { TLinkList* sList = (TLinkList*)list; LinkListNode* ret = NULL; int i=0; if((sList!=NULL)&&(pos>=0)&&(pos <sList->length)) { LinkListNode* current = (LinkListNode*)sList; //让current指向头结点 for(i=0;i<pos;i++) { current = current->next; } ret = current->next; } return ret; } LinkListNode* LinkList_Delete(LinkList* list, int pos) { TLinkList* sList = (TLinkList*)list; LinkListNode* ret = NULL; int i=0; if((sList!=NULL)&&(pos>=0)&&(pos <sList->length)) { LinkListNode* current = (LinkListNode*)sList; //让current指向头结点 for(i=0;i<pos;i++) { current = current->next; } ret = current->next; current->next = ret->next; sList->length--; } return ret; }
LinkList.h
#ifndef _LINKLIST_H_ #define _LINKLIST_H_ typedef void LinkList; typedef struct _tag_LinkListNode LinkListNode; struct _tag_LinkListNode { LinkListNode* next; }; LinkList* LinkList_Create(); 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 // __2_1_H_
main函数里写个测试程序
#include <stdio.h> #include <stdlib.h> #include "SeqList.h" #include "LinkList.h" //定义数据元素,包含next指针和本身数据元素 typedef struct value { LinkListNode header; int v; }sv; int main() { int i=0; LinkList* list = LinkList_Create(); sv v1; sv v2; sv v3; sv v4; sv v5; v1.v = 1; v2.v = 2; v3.v = 3; v4.v = 4; v5.v = 5; LinkList_Insert(list,(LinkListNode*)&v1,0); LinkList_Insert(list,(LinkListNode*)&v2,0); LinkList_Insert(list,(LinkListNode*)&v3,0); LinkList_Insert(list,(LinkListNode*)&v4,0); LinkList_Insert(list,(LinkListNode*)&v5,0); //头插法 54321 /* LinkList_Insert(list,(LinkListNode*)&v1,LinkList_length(list)); LinkList_Insert(list,(LinkListNode*)&v2,LinkList_length(list)); LinkList_Insert(list,(LinkListNode*)&v3,LinkList_length(list)); LinkList_Insert(list,(LinkListNode*)&v4,LinkList_length(list)); LinkList_Insert(list,(LinkListNode*)&v5,LinkList_length(list)); //尾插法12345 */ for(i=0; i<LinkList_Length(list);i++) { sv* p = (sv*)LinkList_Get(list,i); printf("%d\n",p->v); } while(LinkList_Length(list)) { sv* pv = (sv*)LinkList_Delete(list,LinkList_Length(list)-1); printf("%d\n",pv->v); } LinkList_Destroy(list); /* int index=0; LinkList* list = LinkList_Create(); int i=0; int j=1; int k=2; int x=3; int y=4; int z=5; SeqList_Insert(list,&i,0); SeqList_Insert(list,&j,0); SeqList_Insert(list,&k,0); SeqList_Insert(list,&x,0); SeqList_Insert(list,&y,0); SeqList_Insert(list,&z,0); for(index=0; index<SeqList_Length(list); index++) { int* p = (int*)SeqList_Get(list,index); printf("%d\n",*p); } while(SeqList_Length(list)>0) { int *p = SeqList_Delete(list,0); printf("%d\n",*p); } SeqList_Destroy(list); */ return 0; }
注意头插法和尾插法的区别。
链表与线性表相比:
优点是无需一次性定制线性表的容量,插入和删除无需移动数据元素
缺点是数据元素必须保存后继元素的位置信息,获取指定数据的元素操作需要顺序访问之前的元素,要从头结点开始。