【C++】链表相关的项目(2.0)

准备工作

首先弄几个可能会需要的头文件:

#include<stdio.h>
#include<stdlib.h> 
#include<string.h>
typedef int ADT; //定义自定义数据类型 


​

​

因为写的是关于链表的项目需要定义一个结构体:

//定义结构体 
typedef struct N
{
	ADT data;
	struct N *next;	
}Node;



​

定义有关链表的结构体:

​
//定义链表结构体 
typedef struct
{
	Node *head, *tail;//定义头尾指针 
	unsigned size;//定义变量 
}List;

​

初始化操作:

//初始化链表函数 
List *init_list(List *lp) 
{
	lp -> head = lp -> tail = (void*)0; //头尾指针为空
    lp -> size = 0;//链表个数为0
    return lp; 
}



​

制作节点(这部分仅仅跟后面的几个操作有关):

​//制作节点 
Node *make_node(ADT d)
{
	Node *np = malloc(sizeof(Node));//申请空间 
	if(!np)//申请成功 
	    return (void*)0;
	np -> data = d;
	np -> next = (void*)0;
	return np;
}

​

​

---------------------------------------------------------------------------------------------------------------------------------

这篇重要的部分来咯~

  • 1.清空链表操作
  • 2.链表头插操作
  • 3.链表尾插操作
  • 4.链表头删操作
  • 5.链表尾删操作
  • 6.查找位置操作
  • 7.插入某元素到指定位置的函数 (插入某元素之后,否则头插)
  • 8.插入某元素到指定位置的函数 (插入某元素之前,否则尾插)方法1 
  • 9.插入某元素到指定位置的函数 (插入某元素之前,否则尾插)方法2 
  • 10.删除某元素之后的第一个元素的函数 
  • 11.删除元素本身,不存在则不删的函数 方法1 
  • 12.删除元素本身,不存在则不删的函数 方法2
  • 13.按序打印链表函数

---------------------------------------------------------------------------------------------------------------------------------

1.0中咱们写到5

2.0从6开始 

~~~~~~~~~~~~~~~~~

NO6 查找位置操作

//6 
//查找操作函数(找位置)
// 定义了一个函数find_element,它接收一个指向List结构体的指针lp和一个ADT类型的值d作为参数。  
// 函数返回一个整型值,表示元素d在链表中的位置(如果找到的话),或者返回0表示未找到。  
int find_element(List *lp, ADT d)    
{    
    // 初始化一个整型变量position为1。这个变量用于跟踪当前正在检查的节点在链表中的位置。  
    // 假设链表至少有一个元素,所以初始位置设为1。  
    int position = 1;   
      
    // 通过lp指针获取链表的头节点,并将其地址赋给Node类型的指针cur。  
    // cur将用于遍历链表。  
    Node *cur = lp->head;   
    
    // 使用while循环遍历链表。循环的条件是cur不为NULL,即当前节点不是链表的末尾。  
    while (cur)   
    {    
        // 如果当前节点的数据域data的值等于要查找的值d,  
        if (cur->data == d)   
        {    
            // 则函数直接返回当前的位置position。  
            // 这里的position是从1开始计数的,符合通常对链表元素位置的理解。  
            return position;   
        }    
    
        // 如果当前节点的数据不等于d,则将cur指针移动到下一个节点。  
        cur = cur->next;   
          
        // 同时,递增position的值,以便在下一次循环中检查下一个节点的位置。  
        position++;   
    }    
    
    // 如果循环结束(即遍历完整个链表),仍然没有找到等于d的节点,  
    // 则函数返回0,表示未找到元素。  
    return 0;   
}

---------------------------------------------------------------------------------------------------------------------------------

NO7 —— NO12(由于这六个模块都需要通过找到某个指针才能实现本身想要的功能,所以我全部归为一类)

//查找指针函数(找某个指针) 
Node *find_in_list(List *lp, ADT d) {
    Node *cur = lp->head; // 将cur指针初始化为链表的头节点,从头开始遍历
    while (cur && cur->data != d) { // 当cur不为空且cur指向的节点数据不等于d时,继续循环
        cur = cur->next; // 将cur指针移动到下一个节点
    }
    return cur; // 如果找到数据等于d的节点,返回该节点的指针;如果没有找到,cur将为NULL,返回NULL
}
//7
//插入某元素之后,否则头插
List *insert_some_element(List *lp, int d, Node *pos) {
    if (pos == (void*)0) // 如果pos是NULL,说明没有找到指定位置或者链表为空
        return push_front_list(lp, d); // 调用另一个函数在链表头部插入新元素d
    Node *new_node = make_node(d); // 根据元素d创建一个新的节点
    new_node->next = pos->next; // 将新节点的next指向pos节点的下一个节点,为插入做准备
    pos->next = new_node; // 将pos节点的next指向新节点,完成插入
    if (pos == lp->tail) // 如果pos是链表的尾部节点
        lp->tail = new_node; // 更新链表的尾部为新节点
    lp->size++; // 链表长度增加1
    return lp; // 返回链表的指针
}
//8
//插入某元素之前,否则尾插 方法1 
List *insert_element_front(List *lp, ADT d, Node *pos) {
    if (pos == (void*)0) // 如果pos是NULL,说明链表为空或者没有找到指定节点
        return push_back_list(lp, d); // 调用另一个函数在链表尾部插入新元素d
    if (pos == lp->head) // 如果pos是头节点
        return push_front_list(lp, d); // 调用另一个函数在头部插入新元素d
    Node *cur = lp->head; // 从链表的头节点开始遍历
    while (cur->next != pos) // 当cur的下一个节点不是pos时,继续遍历
        cur = cur->next; // 移动到下一个节点
    Node *new_node = make_node(d); // 创建一个新节点,数据为d
    new_node->next = pos; // 将新节点的next指向pos节点,为插入做准备
    cur->next = new_node; // 将cur节点的next指向新节点,完成插入
    lp->size++; // 链表长度增加1
    return lp; // 返回链表的指针
}
//9
//插入某元素之前,否则尾插 方法2
List *insert_element_front2(List *lp, ADT d, Node *pos) {
    if (pos == (void*)0) // 如果链表为空
        return push_back_list(lp, d); // 在尾部插入新元素d
    Node *new_node = make_node(pos->data); // 创建一个新节点,复制pos节点的数据
    new_node->next = pos->next; // 新节点的next指向pos节点的下一个节点
    pos->next = new_node; // 将pos节点的next指向新节点,完成插入
    pos->data = d; // 更新pos节点的数据为新元素d
    if (pos == lp->tail) // 如果pos是链表的尾部节点
        lp->tail = new_node; // 更新链表的尾部为新节点
    lp->size++; // 链表长度增加1
    return lp; // 返回链表的指针
}
//10
//删除某元素之后的第一个元素的函数 
Node *del_element_next(List *lp, Node *pos) {
    if (pos == (void*)0 || pos == lp->tail) // 如果pos是NULL或pos是链表的尾部节点,不能删除
        return (void*)0;
    Node *del = pos->next; // del指向pos节点的下一个节点,即要删除的节点
    pos->next = del->next; // 将pos节点的next指向del的下一个节点,从而跳过del节点
    if (del == lp->tail) // 如果del是链表的尾部节点
        lp->tail = pos; // 更新链表的尾部为pos节点
    free(del); // 释放del节点的内存
    lp->size--; // 链表长度减少1
    return lp; // 返回链表的指针
}
//11
//删除元素本身,不存在则不删的函数 方法1 
List *del_element_self(List *lp, Node *pos) {
    if (pos == (void*)0) // 如果pos是NULL,不执行删除
        return (void*)0;
    if (pos == lp->head) // 如果pos是头节点,使用特殊方法删除
        return pop_front_first(lp);
    Node *cur = lp->head; // 从链表的头节点开始遍历
    while (cur->next != pos) // 找到pos节点的前一个节点
        cur = cur->next;
    cur->next = pos->next; // 将cur节点的next指向pos的下一个节点,从而删除pos节点
    if (pos == lp->tail) // 如果pos是尾部节点
        lp->tail = cur; // 更新链表的尾部为cur节点
    free(pos); // 释放pos节点的内存
    lp->size--; // 链表长度减少1
    return lp; // 返回链表的指针
}
//12
//删除元素本身,不存在则不删的函数 方法2 
List *del_element_self2(List *lp, Node *pos) {
    if (pos == (void*)0) // 如果pos是NULL,不执行删除
        return (void*)0;
    if (pos == lp->tail) // 如果pos是尾部节点,使用特殊方法删除
        return pop_back_last(lp);
    Node *del = pos->next; // del指向pos节点的下一个节点
    pos->data = del->data; // 将del节点的数据复制到pos节点
    pos->next = del->next; // 将pos节点的next指向del的下一个节点,从而跳过del节点
    if (del == lp->tail) // 如果del是尾部节点
        lp->tail = pos; // 更新链表的尾部为pos节点
    free(del); // 释放del节点的内存
    lp->size--; // 链表长度减少1
    return lp; // 返回链表的指针
}

---------------------------------------------------------------------------------------------------------------------------------

NO13 按序打印链表函数

//13
//按序打印链表函数
// 定义print_list函数,它接受一个指向List类型的指针lp作为参数  
// List类型在代码段之外定义,我们假设它包含至少两个成员:head(指向链表首节点的指针)和size(链表中节点的数量)  
void print_list(const List *lp)   
{  
    // 打印一条分隔线,用于在输出中区分不同的链表内容  
    printf("------------------------------------------<<<<<----------------------------------------------------------\n");  
  
    // 定义一个Node类型的指针current,并将其初始化为lp->head,即链表的头节点  
    // 假设Node是链表节点的类型,包含至少两个成员:data(存储的数据,这里假设是歌曲的ID)和next(指向下一个节点的指针)  
    Node *current = lp -> head;  
  
    // 检查链表是否为空(即头节点是否为NULL)  
    if(current)  
    {  
        // 如果链表不为空,首先打印出链表中歌曲的第一个数据 
        // 注意,这里假设lp->size是正确的,即它确实反映了链表中节点的数量  
        printf("链表储存了%d个数据:%d", lp->size, current->data);  
  
        // 将current指针移动到下一个节点,以便开始打印后续的链表数据
        current = current -> next;  
  
        // 使用while循环遍历链表中的剩余节点  
        while(current)  
        {  
            // 打印当前节点的数据,并在前面加上箭头以表示顺序  
            printf("->%d", current->data);  
  
            // 将current指针移动到下一个节点,继续循环直到链表末尾  
            current = current -> next;  
        }  
  
        // 打印换行符,结束当前链表的打印  
        printf("\n");  
    }   
    else  
    {  
        // 如果链表为空,则打印一条消息说明链表列表为空  
        printf(" 链表序列为空!\n");  
    }  
  
    // 打印另一条分隔线,用于在输出中区分不同的链表内容  
    printf("------------------------------------------<<<<<----------------------------------------------------------\n");   
}

-------------------------------------------------------------------------------------------------------------------------------- 

这一篇解释代码的方法与上一篇略有不同,但我觉得这样放在源代码里面解释估计更方便理解。

个人认为想要更好的理解链表一定一定要通过画图,因为画图会更加直观,这里就不给大家展示。sorry~

这篇重点到这基本就结束了,下一篇我大概会附上我的完整代码让大家看看完整的运行结果是什么样的。

感谢各位观看!!         

ps:  想要观看第一篇的朋友  请点击                   

▬▬▬▬.◙.▬▬▬▬
       ▂▄▓▄▂
 ◢◤█████▄▄▄◢◤ 
 █小迟专用直升机█▀▀╬ 
  ◥██████◤
  ══╩══╩═══

 ~~~未完待续~~~~

  • 31
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值