数据结构(链表)

该文详细介绍了单向链表的基本操作,包括创建空链表、在指定位置插入节点、删除指定位置节点、查找数据位置、遍历链表、转置链表以及清空链表等。同时,文中强调了错误处理和内存管理的重要性,确保链表操作的正确性和稳定性。
摘要由CSDN通过智能技术生成

数据结构(链表)

解决:长度固定的问题,插入和删除麻烦的问题

结构

逻辑结构:线性结构
存储结构:链式存储结构 在内存当中存储是连续的 数组

结构体

typedef int datatype;
typedef struct node_t
{
datatype data;//数据域
struct node_t *next;//指针域,指向自身结构体的指针
}link_node_t,*link_list_t;

创建一个空的单向链表(有头单向链表)

link_node_t *CreateEpLinkList()
{
    //思想:创建一个节点,作为头节点
    link_list_t p=(link_list_t)malloc(sizeof(link_node_t));
    if(p==NULL)
    {
        perror("CreateEpLinkList err");
        return NULL;
    }
    p->next=NULL;
    return p;
}

操作

在指定位置插入

1.容错判断(判越界)
2.创建一个新节点pnew用于存储数据
 link_list_t pnew =(link_list_t)malloc(sizeof(link_node_t));
    pnew->data=data
3.将头指针移动到插入位置的前一个节点
4.插入操作(先连后面再连前面)

求链表长度:(有头遍历)

int LengthLinkList(link_node_t *p)
{
    int len=0;
    while(p->next !=NULL)
    {
        p=p->next;
        len++;
    }
    return len;
}

容错判断:

if(post<0|| post>LengthLinkList(p))
    {
        perror("InsertIntoPostLinkList err");
        return -1;
    }

将头指针遍历到插入位置的前一个节点:

for (int i = 0; i < post; i++)
{
    p=p->next;
}

插入操作:

pnew->data=data;
pnew->next ==NULL;
pnew->next =p->next;
p->next=pnew;

分段代码:

//向单向链表的指定位置插入数据
//p 保存链表的头指针 post 插入的位置 data 插入的数据
int InsertIntoPostLinkList(link_node_t *p,int post, datatype data)
{
    link_list_t pnew = NULL;
    //1.容错判断
    if(post<0|| post>LengthLinkList(p))
    {
        perror("InsertIntoPostLinkList err");
        return -1;
    }
    //2.将头指针移动到插入位置的前一个节点
    for (int i = 0; i < post; i++)
    {
        p=p->next;
    }
    //3.创建新节点保存插入数据
    pnew =(link_list_t)malloc(sizeof(link_node_t));
    if(pnew ==NULL)
    {
        perror("pnew malloc err");
        return -1;
    }
    pnew->data=data;
    pnew->next ==NULL;
    //4.将新节点插入指定位置
    pnew->next =p->next;
    p->next=pnew;
    return 0;    
}

删除指定位置的数据

1.容错判断(判越界、判空)
2.创建一个删除指针pdel
3.定位到删除位置的前一个节点
4.删除操作

判断单向链表是否为空 1 代表空 0 代表非空

判断单向链表是否为空 1 代表空 0 代表非空
int IsEpLinkList(link_node_t *p)
{
    return p->next==NULL;
}

容错判断:

if(post<0 || post>=LengthLinkList(p) || IsEpLinkList(p))
{
    perror("DeletePostLinkList err");
    return -1;
}

将头指针遍历到删除位置的前一个节点:

for(int i=0;i<post;i++)
{
    p=p->next;
}

删除操作:

pdel=p->next;
//跨过被删除节点
p->next = pdel->next;
//释放被删除节点
free(pdel);
pdel=NULL;

分段代码

删除单向链表中指定位置的数据 post 代表的是删除的位置
int DeletePostLinkList(link_node_t *p, int post)
{
    //1.容错判断
    if(post<0 || post>=LengthLinkList(p) || IsEpLinkList(p))
    {
        perror("DeletePostLinkList err");
        return -1;
    }
    //2.遍历到删除位置前一个节点
    for(int i=0;i<post;i++)
    {
        p=p->next;
    }
    //3.定义一个指针指向被删除节点
    link_list_t pdel=p->next;
    //4.跨过被删除节点
    p->next = pdel->next;
    //5.释放被删除节点
    free(pdel);
    pdel=NULL;
}

删除指定数据

1.定义一个代替指针q指向p的next
   定义一个删除指针pdel
2.用q无头遍历
3.if(q->data==data)
         执行删除操作
          q指针指向下一个节点
  p指向下一个节点
  q指向p下一个节点

分段代码

//删除单向链表中出现的指定数据,data 代表将单向链表中出现的所有 data 数据删除
int DeleteDataLinkList(link_node_t *p, datatype data)
{
    //1.定义指针q,q指向p的next
    link_list_t q =p->next;
    link_list_t pdel =NULL;
    //2.用q遍历无头链表
    while(q != NULL)
    {
        if(q->data == data)
        {
            pdel=q;//1.将pedl指向被删除节点
            p->next=pdel->next;//2.跨过被删除节点
            free(pdel);//3.释放被删除节点
            pdel=NULL;
            q=p->next;//4.q指向链表删除后的下一个节点
        }
        else
        {
            p=p->next;//p走向下一个节点
            q=p->next;//q重新指向p的下一个节点
        }
        
    }
    return 0;
}

修改指定位置的数据

1.容错判断(判越界)
2.for遍历到修改节点的位置
3.修改操作

用头指针遍历到修改节点位置:

for(int i=0;i<=post;i++)
    {
        p=p->next;
    }

修改操作:

p->data = data;

分段代码

//修改指定位置的数据 post 被修改的位置 data 修改成的数据
int ChangePostLinkList(link_node_t *p, int post, datatype data)
{
    //1.容错判断
    if(post<0 || post>=LengthLinkList(p))
    {
        perror("ChangePostLinkList err");
        return -1;
    }
    //2.遍历到修改的节点位置
    for(int i=0;i<=post;i++)
    {
        p=p->next;
    }
    //3.修改数据
    p->data = data;
    return 0;
}

查找指定数据出现的位置

1.定义一个下标指针post
2.有头遍历
3.判断p->data==data
3.计数post++

分段代码

查找指定数据出现的位置 data 被查找的数据 //search 查找
int SearchDataLinkList(link_node_t *p, datatype data)
{
    int post =0;
    while(p->next != NULL)          
    {                              
        p=p->next;                       
        if(p->data==data)
            return post;
        post++;
    }
    return -1;
}

遍历

1.有头遍历

分段代码

//遍历单向链表
void ShowLinkList(link_node_t *p)
{
    p=p->next;
    while(p != NULL)
	{
        
		printf("%d ",p->data);
		p = p->next;
	}
	printf("\n");
}

转置

1.创建替代指针q
   创建临时指针temp存放q的下一个节点
2.断头操作
3.遍历无头链表
4.转置操作(先连后面再连前面)
5.将q指向temp存储的q的下一个节点

断头操作:

p->next=null

转置操作:

q->next=p->next
p->next=q转置操作:
q->next=p->next
p->next=q

分段代码

转置链表
void ReverseLinkList(link_node_t *p)
{
    //1.断开前保存头节点的下一个节点的地址
    link_list_t q =p->next;
    link_list_t temp =NULL;
    //2.断开链表
    p->next=NULL;
    //3.遍历无头链表
    while(q != NULL)
    {
        //提前保存q的下一个节点
        temp =q->next;
        //先连后面再连前面
        q->next=p->next;
        p->next=q;
        //将q移动到无头链表的下一个节点
        q=temp;
    }
}

清空链表

1.定义一个删除指针pdel
2.有头遍历
3.清空操作

分段代码

//清空单向链表
void ClearLinkList(link_node_t *p)
{
    link_list_t pdel =NULL;
    while (p->next !=NULL)//遍历一遍
    {
        pdel=p->next;//pdel指向当前节点
        p->next=pdel->next;//进到下一个节点
        //3.释放被删除节点
        free(pdel);
        pdel=NULL;
    }    
}

总代码

//1.创建一个空的单向链表(有头单向链表)
link_node_t *CreateEpLinkList()
{
    //思想:创建一个节点,作为头节点
    link_list_t p=(link_list_t)malloc(sizeof(link_node_t));
    if(p==NULL)
    {
        perror("CreateEpLinkList err");
        return NULL;
    }
    p->next=NULL;
    return p;
}

//2.求单向链表长度的函数
int LengthLinkList(link_node_t *p)
{
    int len=0;
    while(p->next !=NULL)
    {
        p=p->next;
        len++;
    }
    return len;
}

//3.向单向链表的指定位置插入数据
//p 保存链表的头指针 post 插入的位置 data 插入的数据
int InsertIntoPostLinkList(link_node_t *p,int post, datatype data)
{
    link_list_t pnew = NULL;
    //1.容错判断
    if(post<0|| post>LengthLinkList(p))
    {
        perror("InsertIntoPostLinkList err");
        return -1;
    }
    //2.将头指针移动到插入位置的前一个节点
    for (int i = 0; i < post; i++)
    {
        p=p->next;
    }
    //3.创建新节点保存插入数据
    pnew =(link_list_t)malloc(sizeof(link_node_t));
    if(pnew ==NULL)
    {
        perror("pnew malloc err");
        return -1;
    }
    pnew->data=data;
    pnew->next ==NULL;
    //4.将新节点插入指定位置
    pnew->next =p->next;
    p->next=pnew;
    return 0;    
}

//4.判断单向链表是否为空 1 代表空 0 代表非空
int IsEpLinkList(link_node_t *p)
{
    return p->next==NULL;
}

//5.删除单向链表中指定位置的数据 post 代表的是删除的位置
int DeletePostLinkList(link_node_t *p, int post)
{
    //1.容错判断
    if(post<0 || post>=LengthLinkList(p) || IsEpLinkList(p))
    {
        perror("DeletePostLinkList err");
        return -1;
    }
    //2.遍历到删除位置前一个节点
    for(int i=0;i<post;i++)
    {
        p=p->next;
    }
    //3.定义一个指针指向被删除节点
    link_list_t pdel=p->next;
    //4.跨过被删除节点
    p->next = pdel->next;
    //5.释放被删除节点
    free(pdel);
    pdel=NULL;
}

//6.遍历单向链表
void ShowLinkList(link_node_t *p)
{
    p=p->next;
    while(p != NULL)
	{
        
		printf("%d ",p->data);
		p = p->next;
	}
	printf("\n");
}

//7.修改指定位置的数据 post 被修改的位置 data 修改成的数据
int ChangePostLinkList(link_node_t *p, int post, datatype data)
{
    //1.容错判断
    if(post<0 || post>=LengthLinkList(p))
    {
        perror("ChangePostLinkList err");
        return -1;
    }
    //2.遍历到修改的节点位置
    for(int i=0;i<=post;i++)
    {
        p=p->next;
    }
    //3.修改数据
    p->data = data;
    return 0;
}

//8.查找指定数据出现的位置 data 被查找的数据 //search 查找
int SearchDataLinkList(link_node_t *p, datatype data)
{
    int post =0;
    while(p->next != NULL)          
    {                              
        p=p->next;                       
        if(p->data==data)
            return post;
        post++;
    }
    return -1;
}

//9.删除单向链表中出现的指定数据,data 代表将单向链表中出现的所有 data 数据删除
int DeleteDataLinkList(link_node_t *p, datatype data)
{
    //1.定义指针q,q指向p的next
    link_list_t q =p->next;
    link_list_t pdel =NULL;
    //2.用q遍历无头链表
    while(q != NULL)
    {
        if(q->data == data)
        {
            pdel=q;//1.将pedl指向被删除节点
            p->next=pdel->next;//2.跨过被删除节点
            free(pdel);//3.释放被删除节点
            pdel=NULL;
            q=p->next;//4.q指向链表删除后的下一个节点
        }
        else
        {
            p=p->next;//p走向下一个节点
            q=p->next;//q重新指向p的下一个节点
        }
        
    }
    return 0;
}

//10.转置链表
void ReverseLinkList(link_node_t *p)
{
    //1.断开前保存头节点的下一个节点的地址
    link_list_t q =p->next;
    link_list_t temp =NULL;
    //2.断开链表
    p->next=NULL;
    //3.遍历无头链表
    while(q != NULL)
    {
        //提前保存q的下一个节点
        temp =q->next;
        //先连后面再连前面
        q->next=p->next;
        p->next=q;
        //将q移动到无头链表的下一个节点
        q=temp;
    }
}

//11.清空单向链表
void ClearLinkList(link_node_t *p)
{
    link_list_t pdel =NULL;
    while (p->next !=NULL)//遍历一遍
    {
        pdel=p->next;//pdel指向当前节点
        p->next=pdel->next;//进到下一个节点
        //3.释放被删除节点
        free(pdel);
        pdel=NULL;
    }
    
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值