C语言:数据结构(单链表)

数据结构:单链表

单链表

基本概念

  • 顺序表:顺序存储的线性表。

  • 链式表:链式存储的线性表,简称链表。

既然顺序存储中的数据因为挤在一起而导致需要成片移动,那很容易想到的解决方案是将数据离散地存储在不同内存块中,然后在用来指针将它们串起来。这种朴素的思路所形成的链式线性表,就是所谓的链表。

顺序表和链表在内存在的基本样态如下图所示:

在这里插入图片描述

链表的分类

根据链表中各个节点之间使用指针的个数,以及首尾节点是否相连,可以将链表细分为如下种类:

  1. 单向链表
  2. 单向循环链表
  3. 双向链表
  4. 双向循环链表

这些不同链表的操作都是差不多的,只是指针数目的异同。以最简单的单向链表为例,其基本示意图如下所示:

在这里插入图片描述

上图中,所有的节点均保存一个指针,指向其逻辑上相邻的下一个节点(末尾节点指向空)。另外

注意到,整条链表用一个所谓的头指针 head 来指向,由 head 开始可以找到链表中的任意一个节点。head 通常被称为头指针。

链表的基本操作,一般包括:

  1. 节点设计
  2. 增删节点
  3. 链表遍历
  4. 销毁链表

下面着重针对这几项常见操作,讲解单向链表的处理。

单链表节点设计

单向链表的节点非常简单,节点中除了要保存用户数据之外(这里以整型数据为例),只需要增加一个指向本类节点的指针即可,如下所示:

typedef int DATA;
typedef struct Node
{
    DATA data;         // 存储数据---数据域
    struct Node *next; // 存储下一个节点的地址---指针域
} NODE;

在这里插入图片描述

单链表初始化

首先,空链表有两种常见的形式。一种是带所谓的头结点的,一种是不带头结点的。所谓的头结点是不存放有效数据的节点,仅仅用来方便操作,如下:

在这里插入图片描述

而不带头结点的空链表如下所示:

在这里插入图片描述

注意:
  • 头指针 head 是必须的,是链表的入口

  • 头节点是可选的,为了方便某些操作

由于头结点是不存放有效数据的,因此如果空链表中带有头结点,那么头指针 head 将永远不变,这会给以后的链表操作带来些许便捷。

下面以带头结点的链表为例,展示单向链表的初始化的示例代码:

/*
@function: int slist_create(NODE** head,DATA data);
@berif: 创建单项链表
@argument: head: 指向头指针变量的地址,用来接收首节点地址
data: 存储在节点中的数据
@return : 成功返回 0
失败返回 -1
*/
int slist_create(NODE **head, DATA data)
{
    NODE *p = (NODE *)malloc(sizeof(NODE));
    if (!p)
    {
        return -1;
    }
    p->data = data;
    p->next = NULL;
    *head = p;
    return 0;
}

单链表增删节点

相对于顺序表需要整片移动数据,链表增删节点只需要修改几个相关指针的指向,动作非常快速。

与顺序表类似,可以对一条链表中的任意节点进行增删操作,示例代码是:

/*
@function: int slist_addHead(NODE** head,DATA data);
@berif: 向链表头部插入一个节点数据
@argument: head: 指向头指针变量的地址,用来接收首节点地址
data: 存储在新节点中的数据
@return : 成功返回 0
失败返回 -1
*/
int slist_addHead(NODE **head, DATA data)
{
    NODE *p = (NODE *)malloc(sizeof(NODE));
    if (!p)
    {
        return -1;
    }
    p->data = data;
    p->next = *head;
    *head = p;
    return 0;
}

/*
@function: int slist_addTail(NODE** head,DATA data);
@berif: 向链表尾部插入一个节点数据
@argument: head: 指向头指针变量的地址,用来接收首节点地址
data: 存储在新节点中的数据
@return : 成功返回 0
失败返回 -1
*/
int slist_addTail(NODE **head, DATA data)
{
    NODE *pNew = (NODE *)malloc(sizeof(NODE));
    if (!pNew)
    {
        return -1;
    }
    pNew->data = data;
    pNew->next = NULL;
    NODE *p = *head, *q = NULL;
    if (!p)
    {
        *head = pNew;
        return 0;
    }
    while (p)
    {
        q = p;
        p = p->next;
    }
    q->next = pNew;
    return 0;
}

/*
@function: int slist_insert(NODE** head,DATA pos ,DATA data);
@berif: 向链表节点值为pos的位置插入一个节点数据data
@argument: head: 指向头指针变量的地址
pos: 插入节点位置的节点数据
data: 存储在新节点中的数据
@return : 成功返回 0
失败返回 -1
*/
int slist_insert(NODE **head, DATA pos, DATA data)
{
    NODE *pNew = (NODE *)malloc(sizeof(NODE));
    if (!pNew)
        return -1;
    pNew->data = data;
    pNew->next = NULL;
    NODE *p = *head, *q = NULL;
    if (!p)
    {
        *head = pNew;
        return 0;
    }
    if (memcmp(&(p->data), &pos, sizeof(DATA)) == 0)
    {
        pNew->next = *head;
        *head = pNew;
        return 0;
    }
    while (p)
    {
        if (memcmp(&(p->data), &pos, sizeof(DATA)) == 0)
        {
            pNew->next = p;
            q->next = pNew;
            return 0;
        }
        q = p;
        p = p->next;
    }
    q->next = pNew;
    return 0;
}

/*
@function: int slist_update(const NODE* head,DATA old,DATA newdata);
@berif: 更新链表数据old 为 newdata
@argument: head: 指向头指针变量
old: 待更新的节点数据
newdata: 更新后的节点数据
@return : 成功返回 0
失败返回 -1
*/
int slist_update(const NODE *head, DATA old, DATA newdata)
{
    NODE *p = NULL;
    if (!(p = slist_find(head, old)))
        return -1;
    p->data = newdata;
    return 0;
}
/*
@function: int slist_delete(NODE** head,DATA data);
@berif: 删除链表中节点值为data的节点
@argument: head: 指向头指针变量的地址
data: 删除节点中的数据
@return : 成功返回 0
失败返回 -1
*/
int slist_delete(NODE **head, DATA data)
{
    NODE *p = *head, *q = NULL;
    if (!p)
        return -1;
    if (memcmp(&(p->data), &data, sizeof(DATA)) == 0)
    {
        *head = p->next;
        free(p);
        return 0;
    }
    while (p)
    {
        if (memcmp(&(p->data), &data, sizeof(DATA)) == 0)
        {
            q->next = p->next;
            free(p);
            return 0;
        }
        q = p;
        p = p->next;
    }
    return -1;
}

注意:

删除链表的节点并不意味着释放其内存,而是将其剔除出链表

单链表的遍历

遍历的意思就是逐个访问每一个节点,对于线性表而言,由于路径唯一的选择就是从头走到尾。因此相当而言比较简单。

下面是单向链表的遍历示例代码,假设遍历每个节点并将其整数数据输出:

/*
@function: NODE* slist_find(const NODE* head,DATA data);
@berif: 查找链表数据data
@argument: head: 指向头指针变量
data: 待查找的数据
@return : 成功返回节点的地址
失败返回NULL
*/
NODE *slist_find(const NODE *head, DATA data)
{
    const NODE *p = head;
    while (p)
    {
        if (memcmp(&(p->data), &data, sizeof(DATA)) == 0)
        {
            return (NODE *)p;
        }
        p = p->next;
    }
    return NULL;
}
/*
@function: void slist_showAll(const NODE* head);
@berif: 遍历链表数据
@argument: head: 指向头指针变量
@return : 无
*/
void slist_showAll(const NODE *head)
{
    const NODE *p = head;
    while (p)
    {
        printf("%d ", p->data);
        p = p->next;
    }
    printf("\n");
}

单链表的销毁

由于链表中的各个节点被离散地分布在各个随机的内存空间,因此销毁链表必须遍历每一个节点,释放每一个节点。

注意:

销毁链表时,遍历节点要注意不能弄丢相邻节点的指针

示例代码如下:

/*
@function: void slist_destroy(NODE** head);
@berif: 回收链表
@argument: head: 指向头指针变量的地址
@return : 无
*/
void slist_destroy(NODE **head)
{
    NODE *p = *head, *q = NULL;
    while (p)
    {
        q = p;
        p = p->next;
        free(q);
    }
    *head = NULL;
}

注意:我们可以使用valgrind进行内存检测,举例:

valgrind ./..

完整代码:

  • singleList.h
#ifndef __SINGLELIST_H
#define __SINGLELIST_H
// 头文件
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef int DATA;
typedef struct node
{
    DATA data;
    struct node *next;
} NODE;
// 链表创建
int slist_create(NODE **, DATA);
// 链表数据添加-头插法
int slist_addHead(NODE **head, DATA data);
// 链表数据添加-尾插法
int slist_addTail(NODE **head, DATA data);
// 链表数据添加-中间插法
int slist_insert(NODE **head, DATA pos, DATA data);
// 链表数据查询
NODE *slist_find(const NODE *head, DATA data);
// 链表数据更新
int slist_update(const NODE *head, DATA old, DATA newdata);
// 链表数据遍历
void slist_showAll(const NODE *head);
// 链表数据删除
int slist_delete(NODE **head, DATA data);
// 链表回收
void slist_destroy(NODE **head);


#endif
  • singleList.c
#include "singleList.h"
/*
@function: int slist_create(NODE** head,DATA data);
@berif: 创建单项链表
@argument: head: 指向头指针变量的地址,用来接收首节点地址
data: 存储在节点中的数据
@return : 成功返回 0
失败返回 -1
*/
int slist_create(NODE **head, DATA data)
{
    NODE *p = (NODE *)malloc(sizeof(NODE));
    if (!p)
    {
        return -1;
    }
    p->data = data;
    p->next = NULL;
    *head = p;
    return 0;
}
/*
@function: int slist_addHead(NODE** head,DATA data);
@berif: 向链表头部插入一个节点数据
@argument: head: 指向头指针变量的地址,用来接收首节点地址
data: 存储在新节点中的数据
@return : 成功返回 0
失败返回 -1
*/
int slist_addHead(NODE **head, DATA data)
{
    NODE *p = (NODE *)malloc(sizeof(NODE));
    if (!p)
    {
        return -1;
    }
    p->data = data;
    p->next = *head;
    *head = p;
    return 0;
}
/*
@function: int slist_addTail(NODE** head,DATA data);
@berif: 向链表尾部插入一个节点数据
@argument: head: 指向头指针变量的地址,用来接收首节点地址
data: 存储在新节点中的数据
@return : 成功返回 0
失败返回 -1
*/
int slist_addTail(NODE **head, DATA data)
{
    NODE *pNew = (NODE *)malloc(sizeof(NODE));
    if (!pNew)
    {
        return -1;
    }
    pNew->data = data;
    pNew->next = NULL;
    NODE *p = *head, *q = NULL;
    if (!p)
    {
        *head = pNew;
        return 0;
    }
    while (p)
    {
        q = p;
        p = p->next;
    }
    q->next = pNew;
    return 0;
}
/*
@function: int slist_insert(NODE** head,DATA pos ,DATA data);
@berif: 向链表节点值为pos的位置插入一个节点数据data
@argument: head: 指向头指针变量的地址
pos: 插入节点位置的节点数据
data: 存储在新节点中的数据
@return : 成功返回 0
失败返回 -1
*/
int slist_insert(NODE **head, DATA pos, DATA data)
{
    NODE *pNew = (NODE *)malloc(sizeof(NODE));
    if (!pNew)
        return -1;
    pNew->data = data;
    pNew->next = NULL;
    NODE *p = *head, *q = NULL;
    if (!p)
    {
        *head = pNew;
        return 0;
    }
    if (memcmp(&(p->data), &pos, sizeof(DATA)) == 0)
    {
        pNew->next = *head;
        *head = pNew;
        return 0;
    }
    while (p)
    {
        if (memcmp(&(p->data), &pos, sizeof(DATA)) == 0)
        {
            pNew->next = p;
            q->next = pNew;
            return 0;
        }
        q = p;
        p = p->next;
    }
    q->next = pNew;
    return 0;
}
/*
@function: NODE* slist_find(const NODE* head,DATA data);
@berif: 查找链表数据data
@argument: head: 指向头指针变量
data: 待查找的数据
@return : 成功返回节点的地址
失败返回NULL
*/
NODE *slist_find(const NODE *head, DATA data)
{
    const NODE *p = head;
    while (p)
    {
        if (memcmp(&(p->data), &data, sizeof(DATA)) == 0)
        {
            return (NODE *)p;
        }
        p = p->next;
    }
    return NULL;
}
/*
@function: int slist_update(const NODE* head,DATA old,DATA newdata);
@berif: 更新链表数据old 为 newdata
@argument: head: 指向头指针变量
old: 待更新的节点数据
newdata: 更新后的节点数据
@return : 成功返回 0
失败返回 -1
*/
int slist_update(const NODE *head, DATA old, DATA newdata)
{
    NODE *p = NULL;
    if (!(p = slist_find(head, old)))
        return -1;
    p->data = newdata;
    return 0;
}
/*
@function: void slist_showAll(const NODE* head);
@berif: 遍历链表数据
@argument: head: 指向头指针变量
@return : 无
*/
void slist_showAll(const NODE *head)
{
    const NODE *p = head;
    while (p)
    {
        printf("%d ", p->data);
        p = p->next;
    }
    printf("\n");
}
/*
@function: int slist_delete(NODE** head,DATA data);
@berif: 删除链表中节点值为data的节点
@argument: head: 指向头指针变量的地址
data: 删除节点中的数据
@return : 成功返回 0
失败返回 -1
*/
int slist_delete(NODE **head, DATA data)
{
    NODE *p = *head, *q = NULL;
    if (!p)
        return -1;
    if (memcmp(&(p->data), &data, sizeof(DATA)) == 0)
    {
        *head = p->next;
        free(p);
        return 0;
    }
    while (p)
    {
        if (memcmp(&(p->data), &data, sizeof(DATA)) == 0)
        {
            q->next = p->next;
            free(p);
            return 0;
        }
        q = p;
        p = p->next;
    }
    return -1;
}
/*
@function: void slist_destroy(NODE** head);
@berif: 回收链表
@argument: head: 指向头指针变量的地址
@return : 无
*/
void slist_destroy(NODE **head)
{
    NODE *p = *head, *q = NULL;
    while (p)
    {
        q = p;
        p = p->next;
        free(q);
    }
    *head = NULL;
}
  • main.c
#include "singleList.h"
int main(void)
{
    NODE *head = NULL;
    if (slist_create(&head, 888) < 0)
    {
        puts("create failed");
        return -1;
    }
    slist_addTail(&head, 999);
    slist_addTail(&head, 222);
    slist_addTail(&head, 666);
    slist_addTail(&head, 777);
    slist_addHead(&head, 555);
    slist_insert(&head, 888, 1024);
    slist_showAll(head);
    DATA data;
    while (0)
    {
#ifdef DELETE
        printf("请输入要删除的数据:");
        scanf("%d", &data);
        if (data == -1)
            break;
        if (slist_delete(&head, data) < 0)
        {
            puts("删除失败,请重试");
            continue;
        }
        slist_showAll(head);
#else
        NODE *pFind = NULL;
        DATA newdata = 512;
        printf("请输入要查找的数据:");
        scanf("%d", &data);
        if (data == -1)
            break;
        // if(!(pFind = slist_find(head,data)))
        if (slist_update(head, data, newdata) == -1)
        {
            puts("查找的数据不存在,请重试");
            continue;
        }
        // printf("查找数据:%d 内存地址:%p\n",pFind -> data, &(pFind -> data));
        slist_showAll(head);
#endif
    }
    slist_destroy(&head);
    puts("====销毁后=====");
    slist_showAll(head);
    return 0;
}

课堂练习2

创建一个单向表,并从键盘接收数字输入,将输入的正整数按从小到大的顺序插入链表,并在输入负整数的时候将其绝对值数据删除。每次输入后,将链表的内容打印到屏幕上。

在这里插入图片描述

解析

此题考查单链表的基本思路,体会链式存储中对于插入和删除的便利性。

参考代码

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct node
{
    int num;
    struct node *next;
} listnode, *linklist;
bool init_list(linklist *phead)
{
    *phead = (linklist)malloc(sizeof(listnode));
    if (*phead == NULL)
        return false;
    (*phead)->next = NULL;
    return true;
}
bool is_empty(linklist head)
{
    return (head->next == NULL);
}
bool insert(linklist head, int x)
{
    linklist new = (linklist)malloc(sizeof(listnode));
    if (new == NULL)
    {
        perror("malloc failed");
        return false;
    }
    new->num = x;
    /********************************
    the single linklist IS empty
    *********************************/
    if (is_empty(head))
    {
        head->next = new;
        new->next = NULL;
    }
    /*********************************
    the single linklist is NOT empty
    **********************************/
    else
    {
        linklist p, q;
        p = head;
        q = p->next;
        while (q != NULL)
        {
            if (q->num < x)
            {
                q = q->next;
                p = p->next;
                continue;
            }
            break;
        }
        new->next = q;
        p->next = new;
    }
    return true;
}
bool delete(linklist head, int x)
{
    if (is_empty(head))
        return false;
    linklist p, q;
    p = head;
    q = p->next;
    while (q != NULL)
    {
        if (q->num != x)
        {
            p = p->next;
            q = q->next;
            continue;
        }
        p->next = q->next;
        free(q);
        return true;
    }
    return false;
}
void show(linklist head)
{
    if (is_empty(head))
        return;
    linklist p = head->next;
    while (p != NULL && p->next != NULL)
    {
        printf("%d-->", p->num);
        p = p->next;
    }
    printf("%d\n", p->num);
}
int main(void)
{
    linklist head;
    init_list(&head);
    int tmp, ret;
    while (1)
    {
        ret = scanf("%d", &tmp);
        if (ret != 1)
            exit(0);
        if (tmp >= 0)
        {
            if (!insert(head, tmp))
                fprintf(stderr, "insertion falied!\n");
            else
                show(head);
        }
        else
        {
            if (!delete (head, -tmp))
                fprintf(stderr, "%d does NOT exist!\n", -tmp);
            else
                show(head);
        }
    }
    fprintf(stderr, "Bye-Bye!\n");
    return 0;
}

链表优缺点

链式存储中,所有节点的存储位置是随机的,他们之间的逻辑关系用指针来确定,跟物理存储位置无关,因此从上述示例代码可以很清楚看到,增删数据都非常迅速,不需要移动任何数据。另外,又由于位置与逻辑关系无关,因此也无法直接访问某一个指定的节点,只能从头到尾按遍历的方式一个个找到想要的节点。简单讲,链式存储的优缺点跟顺序存储几乎是相对的。

总结其特点如下:

优点

  1. 插入、删除时只需要调整几个指针,无需移动任何数据
  2. 当数据节点数量较多时,无需一整片较大的连续内存空间,可以灵活利用离散的内存
  3. 当数据节点数量变化剧烈时,内存的释放和分配灵活,速度快

缺点

  1. 在节点中,需要多余的指针来记录节点之间的关联。
  2. 所有数据都是随机存储的,不支持立即访问任意一个随机数据。

循环单向链表

所谓的循环,指得是将链表末尾节点的后继指针指向头结点。比如,单向链表变成循环链表的示意

图如下所示:

在这里插入图片描述

循环链表的操作跟普通链表操作基本上是一致的,只要针对循环特性稍作修改即可。

  • sclist.h
#ifndef __SCLIST_H
#define __SCLIST_H
typedef int DATA;
typedef struct node
{
    DATA data;
    struct node *next;
} NODE;
// 链表创建
int sclist_create(NODE **, DATA);
// 链表数据添加
int sclist_insert(NODE **head, DATA data);
// 链表数据查询
NODE *sclist_find(const NODE *head, DATA data);
// 链表数据更新
int sclist_update(const NODE *head, DATA old, DATA newdata);
// 链表数据遍历
void sclist_showAll(const NODE *head);
// 链表数据删除
int sclist_delete(NODE **head, DATA data);
// 链表回收
void sclist_destroy(NODE **head);
#endif
  • sclist.c
#include "sclist.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/*
@function: int sclist_create(NODE** head,DATA data);
@berif: 创建单项链表
@argument: head: 指向头指针变量的地址,用来接收首节点地址
data: 存储在节点中的数据
@return : 成功返回 0
失败返回 -1
*/
int sclist_create(NODE **head, DATA data)
{
    if (*head)
        return -1;
    NODE *p = (NODE *)malloc(sizeof(NODE));
    if (!p)
    {
        return -1;
    }
    p->data = data;
    p->next = p;
    *head = p;
    return 0;
}
NODE *sclist_findtail(const NODE *head)
{
    const NODE *p = head, *q = NULL;
    while (p)
    {
        q = p;
        p = p->next;
        if (p == head)
            break;
    }
    return (NODE *)q;
}
/*
@function: int sclist_insert(NODE** head,DATA data);
@berif: 向链表节点值为pos的位置插入一个节点数据data
@argument: head: 指向头指针变量的地址
data: 存储在新节点中的数据
@return : 成功返回 0
失败返回 -1
*/
int sclist_insert(NODE **head, DATA data)
{
    NODE *tail = sclist_findtail(*head);
    if (!tail)
        return sclist_create(head, data);
    NODE *pNew = (NODE *)malloc(sizeof(NODE));
    if (!pNew)
        return -1;
    pNew->data = data;
    pNew->next = *head;
    tail->next = pNew;
    // *head = pNew;
    return 0;
}
/*
@function: NODE* sclist_find(const NODE* head,DATA data);
@berif: 查找链表数据data
@argument: head: 指向头指针变量
data: 待查找的数据
@return : 成功返回节点的地址
失败返回NULL
*/
NODE *sclist_find(const NODE *head, DATA data)
{
    const NODE *p = head;
    while (p)
    {
        if (memcmp(&(p->data), &data, sizeof(DATA)) == 0)
        {
            return (NODE *)p;
        }
        p = p->next;
        if (p == head)
            break;
    }
    return NULL;
}
/*
@function: int sclist_update(const NODE* head,DATA old,DATA newdata);
@berif: 更新链表数据old 为 newdata
@argument: head: 指向头指针变量
old: 待更新的节点数据
newdata: 更新后的节点数据
@return : 成功返回 0
失败返回 -1
*/
int sclist_update(const NODE *head, DATA old, DATA newdata)
{
    NODE *p = NULL;
    if (!(p = sclist_find(head, old)))
        return -1;
    p->data = newdata;
    return 0;
}
/*
@function: void sclist_showAll(const NODE* head);
@berif: 遍历链表数据
@argument: head: 指向头指针变量
@return : 无
*/
void sclist_showAll(const NODE *head)
{
    const NODE *p = head;
    while (p)
    {
        printf("%d ", p->data);
        p = p->next;
        if (p == head)
            break;
    }
    printf("\n");
}
/*
@function: int sclist_delete(NODE** head,DATA data);
@berif: 删除链表中节点值为data的节点
@argument: head: 指向头指针变量的地址
data: 删除节点中的数据
@return : 成功返回 0
失败返回 -1
*/
int sclist_delete(NODE **head, DATA data)
{
    NODE *p = *head, *q = NULL;
    if (!p)
        return -1;
    NODE *tail = sclist_findtail(*head);
    if (memcmp(&(p->data), &data, sizeof(DATA)) == 0)
    {
        if (*head == tail)
        {
            *head = NULL;
            free(p);
            return 0;
        }
        tail->next = (*head)->next;
        *head = p->next;
        free(p);
        return 0;
    }
    while (p)
    {
        if (memcmp(&(p->data), &data, sizeof(DATA)) == 0)
        {
            q->next = p->next;
            free(p);
            return 0;
        }
        q = p;
        p = p->next;
        if (p == *head)
            break;
    }
    return -1;
}
/*
@function: void sclist_destroy(NODE** head);
@berif: 回收链表
@argument: head: 指向头指针变量的地址
@return : 无
*/
void sclist_destroy(NODE **head)
{
    NODE *tail = sclist_findtail(*head);
    if (!tail)
    {
        return;
    }
    tail->next = NULL; // 将单向循环链表拆成单向链表
    NODE *p = *head, *q = NULL;
    while (p)
    {
        q = p;
        p = p->next;
        free(q);
    }
    *head = NULL;
}
  • sclist_main.c
#include <stdio.h>
#include <stdlib.h>
#include "sclist.h"
#define DELETE
extern int play_game(NODE **head, DATA num);
int main(int argc, char **argv)
{
    NODE *head = NULL;
    if (sclist_create(&head, 888) < 0)
    {
        puts("create failed");
        return -1;
    }
    sclist_insert(&head, 999);
    sclist_insert(&head, 222);
    sclist_insert(&head, 666);
    sclist_insert(&head, 777);
    sclist_showAll(head);
    DATA data;
    while (0)
    {
#ifdef DELETE
        printf("请输入要删除的数据:");
        scanf("%d", &data);
        if (data == -1)
            break;
        if (sclist_delete(&head, data) < 0)
        {
            puts("删除失败,请重试");
            continue;
        }
        sclist_showAll(head);
#else
        NODE *pFind = NULL;
        DATA newdata = 512;
        printf("请输入要查找的数据:");
        scanf("%d", &data);
        if (data == -1)
            break;
        // if(!(pFind = slist_find(head,data)))
        if (slist_update(head, data, newdata) == -1)
        {
            puts("查找的数据不存在,请重试");
            continue;
        }
        // printf("查找数据:%d 内存地址:%p\n",pFind -> data, &(pFind -> data));
        slist_showAll(head);
#endif
    }
    sclist_destroy(&head);
    puts("====销毁后=====");
    sclist_showAll(head);
    puts("====PlayGame=====");
    NODE *pHead = NULL;
    for (int i = 1; i <= atoi(argv[1]); i++)
        sclist_insert(&pHead, i);
    sclist_showAll(pHead);
    DATA last = play_game(&pHead, 5);
    printf("最后一个元素:%d\n", last);
    sclist_destroy(&pHead);
    puts("====销毁后=====");
    sclist_showAll(pHead);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值