动态链表的增删改查,打印销毁等基本操作及代码模块化(完整C语言代码!)


首先介绍一些链表的基本知识,然后通过程序实现链表操作的基本功能,增删改查,打印等等操作,并模块化来深化这部分知识点。


链表基础知识


1、由一张内存图展开
单向链表内存图
(1)链表有一个“头指针”变量,如果不提供“头指针”,整个链表都无法访问;
(2)链表的每个元素成为“结点”,每个结点包括数据和下一个结点的地址。末尾的结点地址部分为NULL(空地址);
(3)链表中个元素在内存中的地址可以是不连续的;

2、链表的建立
(1)静态链表:所有结点在程序中定义的,不是临时开辟的,也不能用完后释放;
(2)动态链表:在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入各结点数据,并建立起前后相链的关系。

3、链表的基本操作
写这个代码的时候,中间因为一个while写成了if真是最后测试一直错误,真是醉了!!!奉上完整代码。有错的地方请指正~测试下来是没错的。

#include <stdio.h>
#include <stdlib.h>

typedef int Datatype;   //如果存其他类型的数据可以在此处直接修改

typedef struct node {
    Datatype data;
    struct node *next;
}Node;

//创建结点
Node* creatNode(Datatype data) {
    Node* p = NULL;
    p = (Node*)malloc(sizeof(Datatype));    //申请内存
    if (p == NULL) {    //安全检查
        return NULL;
    }
    p->data = data;     //赋值
    p->next = NULL;
    return p;
}
//打印链表
void printList(Node* head) {
    Node* p = head;
    if (head == NULL) {
        return;
    }
    while(p != NULL) {
        printf("%d\n",p->data);
        p = p->next;
    }
    return;
}
//在一个结点后插入新结点
int insertNodeBehind(Node* p,Node* pnew) {
    if (p == NULL || pnew == NULL) {
        return -1;
    }
    if (p->next != NULL) {
        pnew->next = p->next;
        p->next = pnew;
    }
    else {
        p->next = pnew;
    }
/*其实此处直接写
    pnew->next = p->next;
    p->next = pnew;
 就可以了,因为若p->next = NULL则pnew->next = NULL*/
    return 0;  
}
//结点后插入一个数据
int insertDataBehind(Node *p,Datatype data) {
    Node* pnew = NULL;
    if (p == NULL) {
        return -1;
    }
    pnew = creatNode(data);
    insertNodeBehind(p,pnew);
    return 0;
}
//返回最后末尾结点的地址
Node* findListTail(Node* phead) {
    if (phead == NULL) {
        return NULL;
    }
    while (phead->next != NULL) {
        phead = phead->next;
    }
    return phead;
}
//插入数据到链表的末尾,**是因为可能会涉及修改头指针,在没有结点的情况下
int listInsertDataAtTail(Node** phead,Datatype data) {
    Node *p = NULL;
    if (phead == NULL) {
        return -1;
    }
    if (*phead == NULL) {
        *phead = creatNode(data);
        return 0;
    }
    p = findListTail(*phead);
    insertDataBehind(p,data);
    return 0;
}

//删除后一个结点
int deleteNodeBehind(Node* p) {
    Node* temp  = NULL;
    if (p == NULL) {
        return -1;
    }
    if (p->next == NULL) {
        return 1;
    }
    temp = p->next;
    p->next = p->next->next;
    free(temp);
    return 0;
}
//返回数据为data的结点的地址
Node* findNode(Node* head,Datatype data) {
    Node* p = NULL;
    if (head == NULL) {
        return NULL;
    }
    p = head;
    while (p->data != data) {
        if (p->next != NULL) {
            p = p->next;
        }
        else {
            return NULL;    //没找到该数据为data的结点
        }
    }
    return p;
}
//改数据
int listChangeData(Node* head,Datatype oldData,Datatype newData) {
    Node* p = NULL;
    if (head == NULL) {
        return -1;
    }
    p = findNode(head, oldData);
    p->data = newData;
    return 0;
}
//返回数据为data的结点的前一个结点的地址
Node* findPrevNode(Node *head,Datatype data) {
    Node* p = NULL;
    if (head == NULL) {
        return NULL;
    }
    p = head;
    while (p->next != NULL) {
        if (p->next->data == data) {
            return p;
        }
        else {
            p = p->next;
        }
    }
    return NULL;
}
//删除链表中第一个数据为data的结点
int listDeleteData(Node** phead,Datatype data) {
    Node* p = NULL;
    Node* temp = NULL;
    if (phead == NULL || *phead == NULL) {
        return -1;
    }
    if ((*phead)->data == data) {
        temp = (*phead);
        (*phead) = (*phead)->next;
        free(temp);
        return 0;
    }
    p = findPrevNode(*phead, data);
    deleteNodeBehind(p);
    free(temp);
    return 0;
}
//销毁链表
int listDestroy(Node **phead) {
    if (phead == NULL || (*phead) == NULL) {
        return 0;
    }
    while ((*phead)->next != NULL) {
        deleteNodeBehind(*phead);
    }
    (*phead) = NULL;
    free(*phead);   //不知道此处有没有错误!
    return 0;
}
int main(int argc, const char * argv[]) {
//  创建结点,查尾,增加结点
    Node* p = NULL;
    listInsertDataAtTail(&p, 1); //调用了creatNode,findListTail,insertNodeBehind
    printList(p);

    listInsertDataAtTail(&p, 2);
    listInsertDataAtTail(&p, 3);
    listInsertDataAtTail(&p, 4);
    listInsertDataAtTail(&p, 5);

    printf("已有节点:1-2-3-4-5\n");
    printList(p);

//    删除
//    printf("删除1后面结点\n");
//    listDeleteData(&p, 1);
//    listDeleteData(&p, 3);
//    printList(p);

//    修改
    printf("修改2为20000\n");
    listChangeData(p, 2, 20000);
    printList(p);

    listDestroy(&p);
    printList(p);
    return 0;
}

output:

1
已有节点:1-2-3-4-5
1
2
3
4
5
修改2为20000
1
20000
3
4
5

终于好了~休息了,休息了~晚安,虽然看客还不多,不过慢慢来,会坚持写下去的,最近这样写下来收获还是很大的,毕竟要给别人看(虽然没人哈哈哈哈),有些知识点也补漏了一些~继续加油!
等有人了,多提提意见各位大牛~谢啦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值