单向链表的设计

何为单向链表

链表是一种数据结构,你可以把它想象成一种动态的数组,此数组大小不固定,可以在需要时动态增加、删除元素。它解决了使用数组时大小固定不可更改的痛点。

单向链表示意图

如上图所示,单向链表主要由一个一个节点组成。每个节点包含一个值 Value 和一个指针 * next ,值 Value 用于存储链表中的数值,指针 * next 用于指向下一个节点。

定义一个指针 * Head 用于指向链表头节点。

头节点的作用:表示单向链表的头部(不存放具体数据)。

设定最后一个节点的 * next 的地址为 NULL ,表示链表末尾。

链表节点

使用结构体定义链表节点:

typedef struct _node
{
	DataType value;		//DataType代表实际中的值类型,例如可以 typedef int DataType
	struct _node *next; //链接到下一个节点
} Node;

随后,将整个链表做一封装:

typedef struct _list {
	Node* head;	//指向链表第一个节点
} List;			//list可以代表整个链表

申请一个节点

Node* CreateNode(DataType value) {
    Node* pNode = (Node*)malloc(sizeof(Node));
    pNode->value = value;
    pNode->next = NULL;
    return pNode;
}

链表初始化

初始化部分,将链表头 *head 设置为 NULL。

void initList(List* pList) {
    assert(pList);	//检验参数合法性
    pList->head = NULL;
}

增加元素

在链表末尾增加元素

尾插,首先我们要创建一个新节点,然后判断链表当前是否有节点,若没有,则直接让第一个节点指向新节点,若有,找到最后一个节点,让他指向新节点。

void add_at_end (List* pList, DataType value) {
    assert(pList);	//检验参数合法性
    Node* pNewNode = CreateNode(value);	//申请新节点存放元素
    Node* last = pList->head;			//last用于标识原链表中的末尾节点
    //判断当前有无非头节点
    if (last) {
        while (last->next) {	//如果last->next不为NULL,说明还不是原链表末尾节点
            last = last->next;	//不是原链表末尾节点,last后移
        }
        last->next = pNewNode;	//找到原链表末尾节点,让其指向已申请的新节点
    } else {	// last为Null,说明只有头节点,直接让头节点指向已申请的新节点
        pList->head = pNewNode;
    }
}

在指定位置增加元素

在给定pos位置后插入值为value的节点,分两步完成:首先找到pos位置的节点,然后再插入,所以要实现这一个功能需要两个函数来共同完成。

pos插入

注意:应该先连接好新节点,再断开原来的指针指向。

void add_at_pos(Node* pos, DataType value) {
    Node* pNewNode = NULL;
    if(pos == NULL) {
        return;
    }
    pNewNode = CreateNode(value);
    
    pNewNode->next = pos->next;
    pos->next = pNewNode;
}
  • 参数 pos 可由函数 FindNode(&list, value) 给出(见下文)。

删除元素

在链表末尾删除元素

尾删,首先判断链表中有没有节点,若没有,直接返回,若有一个节点,直接让第一个节点指向NULL,若有多个节点,则需要记录下倒数第二个节点,让它指向NULL。

尾删

void del_at_end(List* pList) {
	assert(pList);	//检验参数合法性
	if (pList->head == NULL) {	//链表中没有节点
		return;
    } else if (pList->head->next == NULL) {	//只有一个节点
        free(pList->head);
        pList->head = NULL;
    } else {                     //多个节点
        Node* pCur = pList->head;
        Node* pPre = NULL;
        while (pCur->next) {
            pPre = pCur;
            pCur = pCur->next;
        }
        free(pCur);
        pPre->next = NULL;
    }
}

在指定位置删除元素

pos删除

void del_at_pos(List* pList, Node* pos) {
    assert(pList);	//检验参数合法性
    if (pos == NULL || pList->head == NULL) {
        return;
    }
    if (pos == pList->head) {
        pList->head = pos->next;
    } else {
        Node* pPrePos = pList->head;
        while (pPrePos && pPrePos->next != pos) {
            pPrePos = pPrePos->next;
        }
        pPrePos->next = pos->next;
    }
    free(pos);
}

删除第一个值为value的节点

要分三种情况:链表为空直接返回、要删除的节点为第一个节点、其它位置的节点。

void del(List* pList, DataType value) {
    assert(pList);	//检验参数合法性
    if (pList->head == NULL) {
        return;
    }
    Node* pPre = NULL;
    Node* pCur = pList->head;
    while (pCur) {
        if (pCur->value == value) {
            if (pCur == pList->head) {	//要删除的是第一个位置的节点
                pList->head = pCur->next;
            } else {
                pPre->next = pCur->next;	//其它位置的情况,让前一个节点指向其后一个节点
            }
            free(pCur);
            return;
        } else {
            pPre = pCur;
            pCur = pCur->next;
        }
    }
}

改变元素的值

更改pos位置节点的value值。

void changevalue(Node* pos, value) {	//此value为更改后的value
    pos->value = value;   
}

查找元素

根据指定的value值,找到对应的节点。

Node* FindNode(List* pList, DataType value){
    assert(pList);	//检验参数合法性
    Node* pCur = pList->head;
    while (pCur) {
        if (pCur->value == value) {
            return pCur;
        }
        pCur = pCur->next;
    }
    return NULL;
} 

打印链表

void printList(List *pList)
{
    assert(pList); //检验参数合法性
    Node *pCur = pList->head;
    while (pCur)
    {
        printf("%d--->", pCur->value);
        pCur = pCur->next;
    }
    printf("\n");
}

清除链表

void destoryList(List *pList)
{
    assert(pList); //检验参数合法性
    if (pList->head = NULL)
    {
        free(pList->head);
        return;
    }
    while (pList->head)
    {
        Node *temp = pList->head->next;
        free(pList->head);
        pList->head = temp;
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值