链表系列

来源:互联网 发布:vb.net 源码 编辑:程序博客网 时间:2024/06/06 20:27

链表


前言:将之前学习的链表方面的知识做一下整理,方便以后复习。

链表中的个对象按照线性顺序排列,数组的线性顺序是由数组下标决定,链表的顺序是由对象里的指针决定。链表为动态集合提供了简单而灵活的表示方法。
基本上一个单向链表包括的操作有

  1. 链表的创建
  2. 链表的销毁
  3. 链表的清空
  4. 获取链表长度
  5. 链表中插入元素
  6. 链表中删除元素
  7. 按位置获取链表中的元素

接下来实现以上单向链表操作:
在之前,需要做一些准备工作,链表中要用到一些结构来存储链表信息。考虑到链表通用性,于是将链表结构与具体数据进行分离的设计,使同一套链表的API能够用于大部分数据链表处理。

typedef void LinkList;typedef struct _LinkListNode{    struct _LinkListNode* next;}LinkListNode;

如果链表节点这样设计,那么数据如何存储?
例如,如何将下面的数据存储到上述链表中,

typedef struct _Student{    char name[40];    int  age;}Student;

对此,可以在Student中添加LinkListNode元素,将Student改造成新的结构体,

typedef struct _Student{    LinkListNode      node;    char              name[20];    int               age;}Student;

可以通过指针的强制转换,实现Student和LinkListNode的相互转换。
到目前为止,实际上已经实现了具体数据与链表API的解耦合。初此之外,还需要一个结构体表示链表的头,结构需包含链表的长度、LinkListNode型的变量来指向链表的第一个元素。于是,结构体如下:

typedef struct _LinkList{    LinkListNode header;    int     length;}HLinkList;

实际上这个数据结构做为内部结构可以被隐藏,外界无法知道内部实现。完成这些准备工作之后,就可以开始单向链表API的实现了。
1.链表的创建
创建链表其实就是创建一个链表头,初始化长度。这里将 typedef void LinkList 以方便表示

LinkList* LinkListCreate()  {    HLinkList *tmp = NULL;    tmp = (HLinkList *)malloc(sizeof(HLinkList));    if (tmp == NULL)    {        return NULL;    }    tmp->length = 0;    tmp->head.next = NULL;    return tmp;}

2.链表的销毁
创建一个,对应的就要销毁一个链表,销毁链表也很简单,就是将LinkListCreate()中malloc的内存释放掉,如下:

void LinkListDestroy(LinkList* list) {    if (list == NULL)    {        return ;    }    free(list);    return ;}

函数中的参数LinkList* list是来标明要操作的时哪一个链表,这里没有销毁元素,因为元素与链表已经分开,所以元素创造者也是元素毁灭者。
3.链表的清空
这个操作其实就是将链表长度置零,head里的next指向NULL;

void LinkListClear(LinkList* list)  {    HLinkList *hList = NULL;    hList = (HLinkList *)list;    if (hList == NULL)    {        return ;    }    hList->header.next = NULL;    hList->length = 0;    return ;}

这里涉及指针的转换,hList = (HLinkList *)list;
4.获取链表长度
将链表头中的长度返回即可

int LinkListLength(LinkList* list)  {    HLinkList *hList = NULL;    hList = (HLinkList *)list;    if (tList == NULL)    {        return -1;    }    return hList->length;}

5.链表的插入
链表的插入是链表一个重要操作。
这里写图片描述

int LinkListInsert(LinkList* list, LinkListNode* node, int pos) {    int             i = 0;    LinkListNode    *current = NULL;    HLinkList       *hList = NULL;    hList = (HLinkList *)list;    if (list==NULL || node==NULL || pos<0)    {        return -1;    }    current = &(hList->header);    for (i=0; i<pos; i++)    {        current = current->next;    }    node->next = current->next;    current->next = node;    hList->length ++;    return 0;}

在三号位置插入元素,就是把插入元素的地址存储到2号位置next指针域,将原来存储在2号位置next指针域的值存到插入元素的next域。
6.链表的删除
这里写图片描述
如图,在三号位置删除三号元素,只需将2号位置的next指向4号位置,同时将3号元素返回,一边对删除元素做其他处理。

LinkListNode* LinkListDelete(LinkList* list, int pos) {    int             i = 0;    LinkListNode    *current = NULL;    LinkListNode    *ret = NULL;    HLinkList       *hList = NULL;    hList = (HLinkList *)list;    if (list==NULL || pos<0)    {        return NULL;    }    current = &(hList->header);    for (i=0; i<pos; i++)    {        current = current->next;    }    ret = current->next;     current->next = ret->next;    hList->length --;    return ret;}

7.按位置获取链表中的元素
这个非常简单,就是按位置找到相应元素然后返回

LinkListNode* LinkListGet(LinkList* list, int pos) {    int             i = 0;    LinkListNode    *current = NULL;    HLinkList       *hList = NULL;    hList = (HLinkList *)list;    if (list==NULL || pos<0)    {        return NULL;    }    current = &(hList->header);     for (i=0; i<pos; i++)    {        current = current->next;    }    return current->next;}
0 0
原创粉丝点击