5.单链表2

单链表涉及的两个结构体:

        描述节点信息的结构体:

                struct node {

                        int data; //节点数据

                        struct node *next; //保存下一个节点的首地址

                };

          描述整个单链表的结构体:

                struct list {

                        struct node *head; //保存头节点的首地址

                        struct node *tail; //保存尾结点的首地址

                 };

 

//list.h:单链表声明
#ifndef __LIST_H
#define __LIST_H
#include <stdio.h>
#include <stdlib.h>
//声明描述节点信息的结构体
typedef struct node {
    int data;//节点数据
    struct node *next;//保存下一个节点的首地址
}node_t;
//声明描述单链表信息的结构体
typedef struct list {
    struct node *head;//保存头节点的首地址
    struct node *tail; //保存尾节点的首地址
}list_t;
//声明操作函数
extern void list_init(list_t *list);//初始化
extern void list_deinit(list_t *list);//释放所有节点内存
extern void list_travel(list_t *list);//遍历
extern void list_add(list_t *list, int data);//顺序插入
extern void list_add_first(list_t *list, int data);//前插
extern void list_add_last(list_t *list, int data);//后插
extern void list_del(list_t *list, int data);//删除data所在的节点
#endif

        vim list.c

//list.c:单链表定义
#include "list.h"
//定义分配新节点内存函数
static node_t *create_node(int data){
    //1.分配节点内存
    node_t *pnew = (node_t *)malloc(sizeof(node_t));
    //2.初始化新节点内存
    pnew->data = data;
    pnew->next = NULL;
    //3.返回新节点内存的首地址
    return pnew;
}
//定义初始化单链表函数
void list_init(list_t *list) {
    //1.给头结点分配内存
    list->head = create_node(0);    
    //2.给尾结点分配内存
    list->tail = create_node(0);    
    //3.头结点指向尾节点
    list->head->next = list->tail;
    list->tail->next = NULL;
}
//定义单链表的遍历函数
void list_travel(list_t *list) {
    for(node_t *pnode = list->head; pnode != list->tail; pnode=pnode->next) {
        //1.定义游标
        node_t *pfirst = pnode;
        node_t *pmid = pfirst->next;
        node_t *plast = pmid->next;
        if(pmid != list->tail) //pmid不指向尾节点那么就是指向有效节点
            printf("%d ", pmid->data);
    }
    printf("\n");
}
//定义顺序插新节点函数
void list_add(list_t *list, int data) {
    //1.创建新节点
    node_t *pnew = create_node(data);
    //2.遍历链表找到要插入的位置,让pmid指向后一个节点,pfirst指向前一个节点
    //那么新节点pnew就插入到pfirst和pmid中间即可
    for(node_t *pnode = list->head; pnode != list->tail; pnode=pnode->next) {
        //1.定义游标
        node_t *pfirst = pnode;
        node_t *pmid = pfirst->next;
        node_t *plast = pmid->next;
        if(pmid->data >= pnew->data || pmid == list->tail/*新节点比前面节点都大*/) {
            pfirst->next = pnew;
            pnew->next = pmid;
            break;
        }
    }
}
//定义前插函数
void list_add_first(list_t *list, int data) {
    //1.创建新节点
    node_t *pnew = create_node(data);
    //临时备份原先的第一个有效节点
    node_t *ptmp = list->head->next;
    //2.将新节点插入到头结点的后面
    list->head->next = pnew; //头结点指向新节点
    pnew->next = ptmp; //新节点指向原先第一个节点
    /*
        pnew->next = list->head->next; //先让新新节点指向原先第一个节点
        list->head->next = pnew; //然后让头结点指向新节点
    */
}
//定义后插函数
void list_add_last(list_t *list, int data) {
    //1.创建新节点
    node_t *pnew = create_node(data);
    //2.遍历链表找到最后一个节点,让pfirst指向后最后一个节点,pmid指向尾节点
    //那么新节点pnew就插入到pfirst和pmid中间即可,也就是新节点插入到原先最后一个节点
    //和尾节点中间
    for(node_t *pnode = list->head; pnode != list->tail; pnode=pnode->next) {
        //3.定义游标
        node_t *pfirst = pnode;
        node_t *pmid = pfirst->next;
        node_t *plast = pmid->next;
        if(pmid == list->tail) {
            pfirst->next = pnew;
            pnew->next = pmid;
            break;
        }
    } 
}
//定义删除节点的函数
void list_del(list_t *list, int data) {
    //1.遍历找到要删除的节点,让pmid指向要删除的节点,这样pfirst指向前一个节点
    //plast指向后一个节点,最后指向让pfirst指向plast即可
    for(node_t *pnode = list->head; pnode != list->tail; pnode=pnode->next) {
        //2.定义游标
        node_t *pfirst = pnode;
        node_t *pmid = pfirst->next;
        node_t *plast = pmid->next;
        if(pmid->data == data && pmid != list->tail/*不能删除尾节点*/) {
            pfirst->next = plast;
            free(pmid); //释放pmid指向的节点内存
            break;
        }
    }
}
//定义释放链表所有节点的函数
void list_deinit(list_t *list) {
    node_t *pnode = list->head;  
    while(pnode) {
        node_t *ptmp = pnode->next; //临时备份下一个节点的地址,不能让链表断开
        free(pnode);//释放当前的节点
        pnode = ptmp; //准备开始释放下一个节点
    }
}

        vim main.c

//main.c:测试
#include "list.h"
int main(void) {
    list_t list; //创建链表
    list_init(&list); //初始化链表
    list_add(&list, 10);
    list_add(&list, 20);
    list_add(&list, 30);
    list_travel(&list);
    list_add_first(&list, 5);
    list_add_first(&list, 3);
    list_travel(&list);
    list_add_last(&list, 40);
    list_add_last(&list, 50);
    list_travel(&list);
    list_del(&list, 20);
    list_travel(&list);
    list_deinit(&list);
    return 0;
}

        vim Makefile

#Makefile
BIN=list
OBJ=main.o list.o
CC=gcc

$(BIN):$(OBJ)
	$(CC) -o $(BIN) $(OBJ)

%.o:%.c
	$(CC) -c -o $@ $<

clean:
	rm $(BIN) $(OBJ)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值