C Datastructure 2 ---- link list(1)

上一篇我们学习了线性表,但是线性表有一个缺点,就是表满了之后就不能再插入了,所以就有了今天的链表(link list)。
链表又分好几种:

  • 单向链表(single link list)
  • 循环链表(circular link list)
  • 双向链表(double link list)
  • 静态链表(static link list)

今天我们先了解下最简单的单项链表。 单项链表github源码链接
定义数据结构

typedef int ElementType;

typedef struct stNode 
{
    ElementType data;
    struct stNode *next;
}stNode;

typedef struct stNode* pstLinkList;

定义接口

BOOL InitList(pstLinkList* pstll, int n);
BOOL IsListEmpty(pstLinkList pstll);

BOOL GetptrList(pstLinkList pstll, int index, pstLinkList* pll);
BOOL GetElem(pstLinkList pstll, int index, ElementType * elem);
BOOL GetIndex(pstLinkList pstll, ElementType elem, int* index);
void GetLength(pstLinkList pstll, int* len);

BOOL InsertElem(pstLinkList pstll, int index, ElementType elem);
BOOL PushElem(pstLinkList pstll, ElementType elem);

BOOL DeletElem(pstLinkList pstll, int index);
BOOL PopElem(pstLinkList pstll);
void ClearList(pstLinkList pstll);

void PrintList(pstLinkList pstll);

具体实现说几个比较重要的函数。

static BOOL CreatNode(pstLinkList* p) /* double ** */
{
    *p = (pstLinkList)malloc(sizeof(stNode));

    if(!(*p))
        return FALSE;

    (*p)->next = NULL;
    (*p)->data = 666;

    return TRUE;
}

这个是为了插入元素时创建一个节点用的。值得注意的是我们需要对节点的地址操作,而不是对节点的拷贝操作。也就是说这个函数的input只能是 pstLinkList* 类型,而不能是pstLinkList类型,否则只是对pstLinkList的一个对象的拷贝进行操作,并不能对我们想要的节点进行内存申请操作。

初始化一个表。

/*
* creat head point to first node
*/
BOOL InitList(pstLinkList* pstll, int n) /* double ** */
{
    int i;
    pstLinkList pstnode,p;

    CreatNode(pstll);//creat head pointer

    p = *pstll;
    for(i=0; i<n; i++)
    {
        CreatNode(&pstnode);

        pstnode->data = i;
        pstnode->next = p->next;

        p->next = pstnode;
    }

    return TRUE;
}

初始化一个表的时候和CreatNode函数都是需要我们提供节点的地址pstLinkList*, 而不是pstLinkList。

博主为了方便插入和删除元素,另外编写了一个查找某一个index下的节点地址的函数。

/*
* if index=0 ,return the head pointer
* pll <----> index =0~len
*/
BOOL GetptrList(pstLinkList pstll, int index, pstLinkList* pll)
{
    int count;
    pstLinkList p;

    p = pstll;//head pointer
    count = 0;
    while(p && index>=0)
    {
        if(index == count)
        {
            *pll = p;

            return TRUE;
        }
        else
        {
            p = p->next;
            count++;
        }
    }

    *pll = NULL;
    return FALSE;
}

接下来就是最关键的插入删除表了。

/*
* insert node at index
*/
BOOL InsertElem(pstLinkList pstll, int index, ElementType elem)
{
    pstLinkList p,pNode;

    /*index>=1 && index <= len+1*/
    if(GetptrList(pstll, index-1, &p))
    {
        CreatNode(&pNode);
        pNode->data = elem;
        pNode->next = p->next;

        p->next = pNode;
        return TRUE;
    }

    return FALSE;   
}

BOOL DeletElem(pstLinkList pstll, int index)
{
    pstLinkList p,pDelNode;

    if(GetptrList(pstll, index-1, &p))
    {
        pDelNode = p->next;

        if(!pDelNode)//in case p is the end 
            return FALSE;

        p->next = pDelNode->next;
        free(pDelNode);
        printf("free ok!\n");
        return TRUE;
    }
    return FALSE;
}

我们同样实现了PushElem、PopElem类似栈的操作,即在表尾插入或者删除一个元素。

BOOL PushElem(pstLinkList pstll, ElementType elem)
{
    int len;

    GetLength(pstll, &len);
    return InsertElem(pstll,len+1,elem);
}

BOOL PopElem(pstLinkList pstll)
{
    int len;

    GetLength(pstll, &len);
    return DeletElem(pstll,len);
}

最后就是销毁一个表,这里尤其要注意,否则容易出现内存溢出(core dumped)错误。
也就是我们malloc了多少次,最终也要free掉多少次。
我的调试方法是设置一个全局变量malloc_cnt,在每一个内存分配的地方打印这个数据

printf("malloc count: %d\n", malloc_cnt++);

同样的,在没一个free的地方搞一个free_cnt,

printf("free count: %d\n", free_cnt++);

最后比较这两个数值就知道那个地方内存出错啦~
最后测试下我们的程序

int main(int argc, char const *argv[])
{
    pstLinkList pstll, pll;

    ElementType elem;
    int index,len;

    if(!InitList(&pstll, 5))
    {
        printf("Init failed!\n");
        ClearList(pstll);

        return 0;
    }

    if(IsListEmpty(pstll))
    {
        printf("this link list is empty!\n");
        ClearList(pstll);

        return 0;
    }

    printf("link list elements are:\n");
    printf("======\n");
    PrintList(pstll);
    printf("\n\n\n");

    GetLength(pstll, &len);
    printf("link list length: %d\n", len);

    if(GetIndex(pstll, 3, &index))
        printf("elem 3 at the index: %d\n",index);
    else
        printf("elem 3 is not existing in the link list\n");

    if(GetElem(pstll, 4, &elem))
        printf("elem at the index 4: %d\n", elem);
    else
        printf("index is not elligal!\n");
    printf("\n\n\n");


    printf("insert elem 90 at index 3: \n");
    InsertElem(pstll, 3, 90);
    printf("now, link list's elem are: \n");
    PrintList(pstll);
    printf("\n\n\n");

    printf("push elem 88 at the end of the link list: \n");
    PushElem(pstll, 88);
    printf("now, link list's elem are: \n");
    PrintList(pstll);
    printf("\n\n\n");

    printf("delet the elem at the index 1: \n");
    DeletElem(pstll, 1);
    printf("now, link list's elem are: \n");
    PrintList(pstll);
    printf("\n\n\n");

    printf("pop elem at the the end of the link list\n");
    PopElem(pstll);
    printf("now, link list's elem are: \n");
    PrintList(pstll);
    printf("\n\n\n");

    printf("clear the list...\n");
    ClearList(pstll);
    printf("link list datastructure exercise is the end...\n");
    printf("see u ^_^ !\n");
    printf("\n\n\n");

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值