C语言实现单链表结点添加增删查改清空等操作

构建一个单链表(没有头结点),链表中存储的是用户输入的整数

一、实现了以下功能:

  1. 链表初始化
  2. 链表判空
  3. 在指定结点之后添加结点
  4. 在指定结点之前添加结点(思路重要)
  5. 删除指定结点p
  6. 结点添加------首添&尾添
  7. 遍历并输出链表
  8. 查找链表的元素------按位序查找(封装起来,在List_Insert和List_DeleteByOrder这两个函数中调用)&按值查找
  9. 删除链表的元素------按值删除&按位删除
  10. 更改链表的指定元素
  11. 在链表的指定位置添加元素
  12. 在链表的指定位置添加元素(引入链表长度pList->size
  13. 链表的清空

二、亮点:用自己定义的数据结构struct _list表示整个链表

    该结构中存放了一个始终指向头结点的指针head,一个始终指向尾结点的指针tail,一个表示单链表长度的变量size

    指针head和tail给链表的结点添加带来方便,不需要遍历整个链表(函数List_AddOnTail)

    变量size给在链表指定位置添加结点带来方便,可以简化代码(函数List_Insert)

三、存在的问题(放在另一个随笔中):
在函数List_DeleteByValue中:链表中存在多个相同的元素相邻时,无法全部删除(重点是相邻,相同元素不相邻时均可删除)

只能删除第偶数个位置的元素

解决方法:

  1. 空间:将原来的链表进行拷贝(或者做一个辅助数组),对原来的链表进行判断,对备份链表进行删除操作(数据量太大时不推荐)
  2. 时间:不改动删除算法,用这个算法对这个链表进行多次操作,直到删除完为止
  3. 再加一个指针:prev,使用三指针方法解决

在codeblocks上编译运行,结果如下:

 代码如下:

# include <stdio.h>
# include <stdlib.h>
# include <stdbool.h>
//定义结构体(结点)
typedef struct _node {
    int value;
    struct _node * next;
} Node;

//定义数据结构struct _list表示整个链表
//存放链表的信息:头结点(如果有的话)或首结点、尾结点、链表长度等等
typedef struct _list
{
    Node* head;//始终指向首结点
    Node* tail;//始终指向尾结点
    int size;//表示链表的长度,用在List_Insert函数中,用来判断输入的位置i是否越界,可以简化代码
} List;
//初始化链表
bool InitList(List* pList)
{
    pList->head = pList->tail = NULL;
    pList->size = 0;
    return true;
}
//判空
bool Empty(List* pList)
{
    return (pList->head==NULL);
}

//在指定结点之后添加结点
bool InsertNextNode(Node* p, int elem)
{
    bool sign = true;
    if(p == NULL)
    {
        sign = false;
    }
    Node* s = (Node*)malloc(sizeof(Node));
    if(s == NULL)//内存分配失败
    {
        sign = true;
    }
    s->value = elem;
    s->next = p->next;
    p->next = s;

    return sign;
}
//在指定节点之前添加结点
/*
偷天换日的操作!
    指定结点的前驱结点是未知的,从头结点遍历的话时间复杂度高O(n)
    虽然结点不能交换位置,但是结点中的数据可以交换位置[O(1)]
*/
bool InsertPriorNode(Node* p, int elem)
{
    bool sign = true;
    if(p == NULL)
    {
        sign = false;
    }
    Node* s = (Node*)malloc(sizeof(Node));
    if(s == NULL)
    {
        sign = false;
    }
    //连接
    s->next = p->next;
    p->next = s;
    //下面两个语句是精髓
    s->value = p->value;//将结点p中的元素复制到s中
    p->value = elem;//p中元素替换为elem

    return sign;
}
//删除指定结点p(局限:当该结点是尾结点时,无法完成操作)
bool DeleteNode(Node* p)
{
    bool sign = true;
    if(p == NULL)
    {
        sign = false;
    }
    Node* q = p->next;//q指向p的后继结点
    p->value = p->next->value;//p结点和它的后继结点交换数据
    p->next = q->next;//将q结点删除
    free(q);

    return sign;
}
//结点添加(尾添加)
Node* List_AddOnTail(List* pList, int number)//传入指针的指针
{
    //分配结点空间,并写入p->value
    Node* p = (Node*)malloc(sizeof(Node));
    p->value = number;
    p->next = NULL;
    //head始终指向首结点,tail始终指向尾结点
    //如果链表是空的,最新分配的结点(p)既是head,也是tail
    if(pList->head == NULL)
    {
        pList->head = p;
        pList->tail = p;
    }
    //如果链表不是空的,只需要处理tail
    else
    {
        pList->tail->next = p;//此时链表的尾结点要指向新分配的结点
        pList->tail = p;//新分配的结点成为链表的tail
    }
    pList->size ++;
    pList->tail->next = NULL;//tail里面的指针必须是NULL

/*  //在链表的尾结点之后添加结点,需要循环,
    Node* last = pList->head;
    if(last)
    {
        while(last->next)
        {
            last = last->next;
        }
        //接上去
        last->next = p;
    }
    else
    {
        pList->head = p;
    }
*/
    return pList->head;
}
//结点添加(头添)
Node* List_AddOnHead(List* pList, int n)
{
    Node* p = (Node*)malloc(sizeof(Node));
    p->value = n;
    p->next = NULL;
    if(pList->head == NULL)
    {
        pList->head = p;
        pList->tail = p;
    }
    else
    {
        p->next = pList->head;
        pList->head = p;
    }
    pList->size ++;
    return pList->head;
}
//遍历输出链表
void List_Print(List* pList)
{
    Node* p;
    for(p=pList->head; p; p=p->next)
    {
        printf("%-5d", p->value);
    }
    printf("\n");
}
//查(按位)
Node* List_GetElem(List* pList, int i)
{
    Node* q;
    if(i<1 || i>pList->size)
        q = NULL;
    else
    {
        Node* p = pList->head;
        int j = 1;
        while(j<i)
        {
            p = p->next;
            j++;
        }
        q = p;
    }

    return q;
}
//查(按值)
bool List_Search(List* pList, int number)
{
    bool isFound = false;
    Node* p;
    for(p=pList->head; p; p=p->next)
    {
        if(p->value == number)
        {
            isFound = true;
            break;
        }
    }
    return isFound;
}
//按值删除元素(仅删除第一个)
void List_DeleteByValue(List* pList, int number)
{
    Node* prev;
    Node* p;
    Node* q;
    for(p=pList->head,q=NULL; p; q=p,p=p->next)
    {
        if(number == p->value)
        {
            if(q)
            {
                q->next = p->next;
            }
            else
            {
                pList->head = p->next;
            }
        free(p);
        break;
        }
    }
}
//更改指定元素
void List_Change(List* pList, int a, int b)
{
    Node* p;
    for(p=pList->head; p; p=p->next)
    {
        if(p->value == a)
        {
            p->value = b;
        }
    }
}
//在指定位置添加元素,引入链表长度(pList->size)
bool List_Insert(List* pList, int i, int elem)
{
    bool sign = true;
    if(i<1 || i>pList->size+1)
        sign = false;
    else if(i == 1)
    {
        Node* s = (Node*)malloc(sizeof(Node));
        s->value = elem;
        s->next = pList->head;
        pList->head = s;
    }
    //找到第i-1个结点
    else
    {
        Node* p = List_GetElem(pList, i-1);//封装 找到第i-1个结点,注意这里传入的参数是List*类型
        sign = InsertNextNode(p,elem);//封装 在第i-1个结点之后插入新结点
    }
    return sign;
}
//按位序删除元素
bool List_DeleteByOrder(List* pList, int i, int* elem)
{
    bool sign = true;
    if(i<1 || i>pList->size+1)
        sign = false;
    else if(i == 1)
    {
        Node* p = pList->head;
        pList->head = p->next;
        free(p);
    }
    //找到第i-1个结点
    else
    {
        Node* p = List_GetElem(pList, i-1);//简单的封装  注意这里传入的参数是List*类型
        if(p==NULL || p->next==NULL)//i值越界或者第i-1个结点没有后继结点
        {
            sign = false;
        }
        Node* q = p->next;
        *elem = q->value;
        p->next = q->next;
        free(q);
    }
    return sign;
}
//清除链表
bool List_Clear(List* pList)
{
    Node* p;
    Node* q;
    bool sign = true;
    if(pList->head == NULL)
        sign = false;
    p = pList->head->next;
    while(p)
    {
        q = p->next;
        free(p);
        p = q;
    }
    pList->head->next = NULL;//注意!!!不能少
    return sign;
}

int main(void)
{
//创建并初始化,输入元素
    List list;
    InitList(&list);
    int number;
    printf("请输入整数(输入-1结束):\n");
    do
    {
        scanf("%d", &number);
        if(number != -1)
        {
            list.head = List_AddOnTail(&list, number);//注意这里要传入head的地址
            //list.head = List_AddOnHead(&list, number);
        }
    }while(number != -1);
//遍历并输出链表
    printf("链表中的元素为:");
    List_Print(&list);
//查(按值)
    printf("\n请输入您要查找的元素:");
    scanf("%d", &number);
    if(List_Search(&list, number) == true)
    {
        printf("找到了!\n");
    }
    else
    {
        printf("没找到!\n");
    }
//查(按位)
    printf("请输入您要查找的位序:");
    int i, elem;
    scanf("%d", &i);
    if(List_GetElem(&list, i) != NULL)
    {
        printf("找到了!该元素是%d\n", List_GetElem(&list, i)->value);//这个地方的写法有问题吗?
    }
    else
    {
        printf("位序越界!\n");
    }
//删除,按元素值
    printf("\n请输入您要删除的元素:");
    scanf("%d", &number);
    if(List_Search(&list, number) == true)
    {
        List_DeleteByValue(&list, number);
        printf("删除成功!当前链表中的元素为:");
        List_Print(&list);
    }
    else
    {
        printf("删除失败!您要删除的元素不存在!\n");
    }

//更改链表元素
    int a, b;
    printf("\n请输入旧元素:");
    scanf("%d", &a);
    if(List_Search(&list, a))
    {
        printf("请输入新元素:");
        scanf("%d", &b);
        List_Change(&list, a, b);
        printf("更改成功!当前链表元素为:");
        List_Print(&list);
    }
    else
    {
        printf("未找到!\n");
    }
//插入元素
    printf("\n请输入您要插入的位置和数字:");
    scanf("%d%d", &i, &elem);
    if(List_Insert(&list, i, elem))
    {
        printf("插入成功!当前链表元素为:");
        List_Print(&list);
    }
    else
    {
        printf("插入失败!\n");
    }
//按位序删除元素
    printf("\n请输入您要删除的结点的位序:");
    scanf("%d", &i);
    if(List_DeleteByOrder(&list, i, &elem))
    {
        printf("删除成功!删除的元素为:%d\n当前链表元素为:", elem);
        List_Print(&list);
    }
    else
    {
        printf("删除失败!\n");
    }

//链表清除
    if(List_Clear(&list))
    {
        printf("\n链表已清空!\n");
    }
    else
    {
        printf("\n清空失败,链表为空\n");
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值