1. 程式人生 > >c語言鏈表升級

c語言鏈表升級

logs ++ reat length 清空 str lib 指針變量 h+

之前的鏈表就是一個普通的帶頭的單向鏈表,我們不自覺的會發現這樣的鏈表有缺陷,有關鏈表的刪除新增查找跟鏈表的結構體內容耦合性太強

什麽意思呢?

比如我們之前的鏈表的結構體

typedef struct _Teacher
{
    int age;
    struct _Teacher *next;
}Teacher;

我們有關鏈表所有的操作都跟這個結構體緊密的相連,如果此刻我們有另一個結構體,裏面的字段都跟這個不一樣,那麽,我們可能還需要對這個新的結構體寫一套鏈表操作?

相當於下面的圖,呵呵,有點醜

技術分享


那麽我們的解決方案是什麽呢?,我們能不能關於不同結構體的所有操作都有一套公共方法呢?

當然是可以的!

在這之前我們必須有一個概念,結構體中的第一個元素的地址就是代表結構體的地址

我們設計一個單純代表數據結構的結構體,這個結構體只有下個對象的地址的指針成員

技術分享

typedef struct _tag_LinkListNode
{
    void * next;
}LinkListNode;

比如此刻我們有一個教師結構體,那麽我們只需要在結構體的第一個成員是上面的LinkListNode對象。
形成下面的數據結構:

技術分享

typedef struct _Teacher
{
    LinkListNode listNode;
    int age;
    char name[50];
}Teacher;

那麽,此刻我們只要在我們的對鏈表的操作將傳過來的Teacher * 指針強轉為LinkListNode *類型,查詢出來的LinkListNode * 指針變量再強轉為Teacher * 對象,從而對LinkListNode形成一套插入刪除查詢的api就可以了
以下是實現的代碼:

接口:

#ifndef _MYLINKLIST_H_
#define _MYLINKLIST_H_

typedef void LinkList;

typedef struct _tag_LinkListNode
{
    struct _tag_LinkListNode* next;
}LinkListNode;


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

實現:

#include "stdio.h"
#include "stdlib.h"
#include "linklist.h"

typedef struct _tag_LinkList
{
    //頭節點
    LinkListNode header;
    int length;
}TLinkList;

/************************************************************************/
/* 創建list並初始化一個頭節點                                           */
/************************************************************************/
LinkList* LinkList_Create()
{
    TLinkList *tlist = (TLinkList *)malloc(sizeof(TLinkList));
    if (tlist == NULL)
    {
        return NULL;
    }
    tlist->length = 0;
    tlist->header.next = NULL;
    return tlist;
}

void LinkList_Destroy(LinkList* list)
{
    if (list == NULL)
    {
        return;
    }
    free(list);
}
/************************************************************************/
/* 清空list鏈表                                                         */
/************************************************************************/
void LinkList_Clear(LinkList* list)
{
    if (list == NULL)
    {
        return;
    }
    TLinkList *tlinkList = (TLinkList *)list;
    tlinkList->length = 0;
    tlinkList->header.next = NULL;

}

int LinkList_Length(LinkList* list)
{
    if (list == NULL)
    {
        return 0;
    }
    TLinkList *tlinkList = (TLinkList *)list;

    return tlinkList->length;
}

int LinkList_Insert(LinkList* list, LinkListNode* node, int pos)
{
    LinkListNode *pre, *cur;
    int i;
    if (list == NULL || node == NULL)
    {
        return -1;
    }
    //校驗下標
    if (pos<0)
    {
        return -2;
    }
    TLinkList *tlinkList = (TLinkList *)list;
    if (pos>tlinkList->length - 1)
    {
        pos = tlinkList->length;
    }
    pre = (LinkListNode *)list;//初始化指向頭節點
    cur = tlinkList->header.next;//初始化指向第一個節點,如果空鏈表指向空
    for (i = 0; i < pos; i++)
    {
        pre = cur;
        cur = cur->next;//最終讓當前指針指向要插入的位置
    }
    pre->next = node;
    node->next = cur;

    tlinkList->length++;
    return 0;
}

LinkListNode* LinkList_Get(LinkList* list, int pos)
{
    LinkListNode *pre, *cur;
    int i;
    if (list == NULL)
    {
        return NULL;
    }
    TLinkList *tlinkList = (TLinkList *)list;
    //校驗下標
    if (pos >= tlinkList->length || pos < 0)
    {
        return NULL;
    }
    cur = tlinkList->header.next;//初始化指向第一個節點,如果空鏈表指向空
    for (i = 0; i < pos; i++)
    {
        cur = cur->next;
    }

    return cur;
}

LinkListNode* LinkList_Delete(LinkList* list, int pos)
{
    LinkListNode *pre, *cur;
    int i;
    if (list == NULL)
    {
        return NULL;
    }
    TLinkList *tlinkList = (TLinkList *)list;
    //校驗下標
    if (pos >= tlinkList->length || pos < 0)
    {
        return NULL;
    }
    pre = (LinkListNode *)list;//初始化指向頭節點
    cur = tlinkList->header.next;//初始化指向第一個節點,如果空鏈表指向空
    for (i = 0; i < pos; i++)
    {
        pre = cur;
        cur = cur->next;
    }
    pre->next = cur->next;
    LinkListNode* curnode = cur;
    tlinkList->length--;
    return curnode;
}

測試代碼

#include "stdio.h"
#include "stdlib.h"
#include "linklist.h"

typedef struct _Teacher
{
    LinkListNode listNode;
    int age;
    char name[50];
}Teacher;
void main()
{
    LinkList* linkList;
    Teacher t1, t2, t3;
    int len;
    int i;
    linkList = LinkList_Create();
    t1.age = 11;
    t2.age = 22;
    t3.age = 33;
    LinkList_Insert(linkList, (LinkListNode*)&t1, 0);
    LinkList_Insert(linkList, (LinkListNode*)&t2, 0);
    LinkList_Insert(linkList, (LinkListNode*)&t3, 0);

    len = LinkList_Length(linkList);

    for (i = 0; i < len; i++)
    {
        Teacher * t = (Teacher *)LinkList_Get(linkList, i);
        printf("cur teacher age=%d\n", t->age);
    }

    LinkList_Delete(linkList, 0);
    LinkList_Delete(linkList, 1);
    len = LinkList_Length(linkList);
    for (i = 0; i < len; i++)
    {
        Teacher * t = (Teacher *)LinkList_Get(linkList, i);
        printf("cur teacher age=%d\n", t->age);
    }
    system("pause");


}

接下來,如果我們有新的結構體,只要在測試代碼那邊做修改,而不需要動我們的核心代碼了。

c語言鏈表升級