C语言单链表实现增删改查

1.概述

单链表使是一种链式存储结构,链表中的数据以结点的方式表示.每个结点由数据域和指针域两部分构成.数据域存储链表的数据元素,指针域存储连接相邻结点的地址.

2.单链表基本组成

typedef struct linklist_t{
    int data;                   // 数据域.
    struct linklist_t *next;    // 指针域.
}LinkList_T;
static LinkList_T *pHead;       // 头指针.

上述代码中我们定义了 pHead 头指针结点.这个结点并不包含实际的数据域,仅仅是为了我们更加方便的操作链表.

3.单链表基础操作

3.1创建单链表

创建单链表的整体思路是依托于pHead头结点,创建结点,并建立结点之间的相互关系.

/*
    创建一个含有n个结点的单链表.
*/
int creatlist(int n)
{
    LinkList_T *pTmp = NULL, *pEnd = NULL;
    int i = 0;
    pHead = (LinkList_T*)malloc(sizeof (LinkList_T));
    if (NULL == pHead)
        return -1;
    pEnd = pHead;
    /*
        整体流程: pEnd指向了pHead头结点.
        首次执行for循环时,设置pTmp的数据域,然后pEnd->next指向pTmp(即首结点).之后pEnd后移指向pTmp.
        第二次执行pTmp时,pEnd指向的是第一个结点(不计算pHead),pEnd->next = pTmp;
        即第一个结点的next指针指向新加入的结点.pEnd = pTmp;pEnd再指向新加入的结点.
        依次类推.即完成了链表的创建.        
    */
    for (i = 0; i < n; i++){
        pTmp = (LinkList_T*)malloc(sizeof (LinkList_T));
        pTmp->data = i;
        pEnd->next = pTmp;
        pEnd = pTmp;
    }
    pEnd->next = NULL;
    return 0;
}

3.2插入新结点

插入结点的思路是找到要插入的位置,先建立待插入结点与下一个结点的关系,然后再建立待插入结点与 上一个结点的位置关系(即断开插入之前的连接关系).

/*
    在链表的第n个结点后面插入新的结点.
*/
int insertlist(int n, int num)
{
    /*
        整体思路:
        1.遍历链表找到要插入的位置.
        2.插入结点.
    */
    LinkList_T *pTmp = NULL, *pNode = NULL;
    int j = 0;

    pTmp = pHead;

    /*
        遍历链表寻找插入位置.
    */
    while (pTmp && (j < n)){
        pTmp = pTmp->next;
        j++;
    }
    /*
        结点不存在.
    */
    if (NULL == pTmp)
        return -1;
    pNode = (LinkList_T *)malloc(sizeof (LinkList_T));
    if (NULL == pNode)
        return -1;

    /*
        插入结点思路:
        pNode->next = pTmp->next;先连接后面的结点.        
        pTmp->next = pNode; 将前面的结点指向自己,即断开了前面结点与之前后面结点的连接.
    */
    pNode->next = pTmp->next;
    pNode->data = num;
    pTmp->next = pNode;
    return 0;
}

3.3删除节点

删除结点的思路是找到待删除的结点,建立待删除结点的前一个结点与待删除结点的后一个结点之间的连接关系.然后删除待删除结点.

/*
    删除单链表的第n个结点.
*/
int dellist(int n)
{
    LinkList_T *pTmp = pHead;
    LinkList_T *pPrv = pHead;
    int j = 0;

    /*
        遍历链表寻找要删除的位置.
        注意此时要保留待删除结点的前一个结点地址.
    */  
    while(pTmp && (j < n)){
        pPrv = pTmp;
        pTmp = pTmp->next;
        j++;
    }
    if (NULL == pTmp)
        return -1;

    /*
        思路: 
        1.获取到要删除的结点和前一个结点. 
        2.建立要删除的结点的后一个结点和其前一个结点的关系.
        3.删除待删结点.
    */
    pPrv->next = pTmp->next;
    pTmp->next = pTmp;
    free(pTmp);
    return 0;
}

3.4修改链表数据

修改链表指定结点数据的思路是遍历链表找到待修改结点,修改数据域.

/*
    修改链表第n个结点的数据域
*/
int changelist(int n, int num)
{

    LinkList_T *pTmp = NULL;
    int j = 0;

    pTmp = pHead;

    /*
        遍历链表找到修改项
    */
    while(pTmp && (j < n)){
        pTmp = pTmp->next;
        j++;
    }


    if (NULL == pTmp)
        return -1;
    /*
        修改数据.
    */
    pTmp->data = num;
    return 0;
}

3.5查询链表

/*
    查询链表
*/
int querylist(void)
{
    LinkList_T *pTmp = NULL;
    int i = 0;
    pTmp = pHead;
    while(pTmp->next){
        pTmp = pTmp->next;
        i++;
        printf ("第 %d 结点的值是 %d \r\n",i, pTmp->data);
    }
    printf ("\r\n");
    return 0;
}

4.测试程序

int main(int argc, char **argv)
{
    creatlist(5);
    querylist();
    insertlist(5, 8);
    querylist();
    changelist(2, 6);
    querylist();
    insertlist(2, 8);
    querylist();
    dellist(3);
    querylist();
}

5测试结果

第 1 结点的值为 0 
第 2 结点的值为 1 
第 3 结点的值为 2 
第 4 结点的值为 3 
第 5 结点的值为 4 

第 1 结点的值为 0 
第 2 结点的值为 1 
第 3 结点的值为 2 
第 4 结点的值为 3 
第 5 结点的值为 4 
第 6 结点的值为 8 

第 1 结点的值为 0 
第 2 结点的值为 6 
第 3 结点的值为 2 
第 4 结点的值为 3 
第 5 结点的值为 4 
第 6 结点的值为 8 

第 1 结点的值为 0 
第 2 结点的值为 6 
第 3 结点的值为 8 
第 4 结点的值为 2 
第 5 结点的值为 3 
第 6 结点的值为 4 
第 7 结点的值为 8 

第 1 结点的值为 0 
第 2 结点的值为 6 
第 3 结点的值为 2 
第 4 结点的值为 3 
第 5 结点的值为 4 
第 6 结点的值为 8 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值