数据结构-单链表

逻辑结构:线性结构

存储结构:链式存储结构

特点:内存不连续,通过指针实现,大小不固定

1.概念

链表又称单链表、链式存储结构,用于存储逻辑关系为“一对一”的数据。

和顺序表不同同,使用链表存储数据,不强制要求数据在内存中集中存储,各个元素可以分散存储在内存中。例如:

需要通过指针实现:

所以在链表中,每个数据元素可以配有一个指针用于找到下一个元素即节点,这意味着,链表上的每个“元素”都长下图这个样子:

2.结构体定义

结构体:
struct node_t
{
	int data ;  //数据域
	struct node _t * next ;    //存放下一个节点的地址
}

3.有头和无头链表

3.1 无头单向链表

每个节点的数据域和指针域都有效

3.2 有头单向链表

存在一个头节点,头节点的数据域无效,但指针域有效

有头和无头链表的区别

  • 有头链表:存在一个头节点,头节点数据域无效,指针域有效。
  • 无头链表:每一个节点的数据域和指针域都有效。

首元结点位置:

  • 不带头结点:首元结点就是第一个节点
  • 带头节点:首元结点是头结点指向的下一个节点(也就是第二个节点),

判空条件:

  • 不带头节点:head == NULL; 首元结点直接为空
  • 带头节点:head->next == NULL; 头结点存在,但是首元结点为空

4.操作

3.1 遍历无头链表

定义一个结构体类型的指针指向首元节点,通过循环遍历打印数据域,每打印一个数据,指针就向后移动一位。

// 遍历无头链表
    linknode_t *p = &A;
    while (p != NULL)
    {
        printf("%d ", p->data);
        p = p->next;
    }

3.2 遍历有头链表

定义一个指针指向头节点,然后跨过头结点,打印输出第二个节点的数据,每打印一个数据,指针就往后移一位

// 遍历有头链表
    // 创建头节点
    linknode_t head;
    head.next = &A;

    // 方法一:
    // 定义指针指向头节点,
    linknode_t *p = &head;
    p = p->next; // 跨过头结点
    while (p != NULL)
    {
        printf("%d ", p->data);
        p = p->next;
    }

    // 方法二
    // 先后移再打印
    linknode_t *p = &head;
    while (p->next != NULL)
    {
        p = p->next;
        printf("%d ", p->data);
    }

    // 方法三
    // 定义指针直接指向首元节点
    linknode_t *p = head.next;
    while (p != NULL)
    {
        printf("%d ", p->data);
        p = p->next;
    }

3.3 尾插法

写一个有头单向链表,用于保存输入的学生成绩,实现一输入学生成绩就创建一个新的节点,将成绩保存起来。再将该节点链接到链表的尾,直到输入-1结束。

要求:每个链表的节点由动态内存分配得到 , 也就是用malloc。

过程:

1. malloc申请结构体大小的空间作为头节点

2. 将新节点放到链表尾部

//(1) 新建节点用来保存数据

//(2) 初始化新节点,也就是保存数据, 指针域置空

//(3) 将新节点和老链表连接,利用尾指针

//(4) 将尾指针移动到新节点

#include <stdio.h>
#include <stdlib.h>

typedef int datatype;

typedef struct node
{
    datatype data;
    struct node *next;
} linknode_t, *linklist_p;

int main(int argc, char const *argv[])
{
    // 开辟头结点
    linknode_t *head = (linknode_t *)malloc(sizeof(linknode_t));
    if (head == NULL)
    {
        perror("head malloc error");
        return -1;
    }

    head->next = NULL;
    int score;
    // 开辟节点,作为尾节点,代替头结点进行移动
    // 一开始,让尾指针指向头结点
    linknode_t *ptail = head;

    while (1)
    {
        scanf("%d", &score);
        if (score == -1)
        {
            break;
        }
        else
        {
            // 新建节点,存入成绩
            linknode_t *pcha = (linknode_t *)malloc(sizeof(linknode_t));
            // 初始化新建节点,存入成绩
            pcha->data = score;
            pcha->next = NULL;
            // 连接,尾指针指向新建节点
            ptail->next = pcha;
            // 移动尾节点,让插入的节点作为新的尾节点
            ptail = pcha;
            // ptail = ptail->next;
        }
    }

    linknode_t *q = head;
    while (q->next != NULL)
    {
        q = q->next;
        printf("%d ", q->data);
    }

    printf("\n");
    return 0;
}

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是使用C语言实现的链表原地逆转的代码: ```c #include <stdio.h> #include <stdlib.h> struct Node { int data; struct Node* next; }; void reverseList(struct Node** head) { struct Node* prev = NULL; struct Node* current = *head; struct Node* next = NULL; while (current != NULL) { next = current->next; current->next = prev; prev = current; current = next; } *head = prev; } void printList(struct Node* head) { while (head != NULL) { printf("%d ", head->data); head = head->next; } printf("\n"); } void push(struct Node** headRef, int newData) { struct Node* newNode = (struct Node*)malloc(sizeof(struct Node)); newNode->data = newData; newNode->next = *headRef; *headRef = newNode; } int main() { struct Node* head = NULL; push(&head, 3); push(&head, 2); push(&head, 1); printf("Original list: "); printList(head); reverseList(&head); printf("Reversed list: "); printList(head); return 0; } ``` 在上述代码中,我们首先定义了一个 `Node` 结构体来表示链表中的每个节点,包括节点的值和指向下一个节点的指针。然后我们定义了 `reverseList` 函数来实现原地逆转链表的功能。该函数接受一个指向指针的指针 `head`,这是因为我们需要通过指针来修改链表的头节点,所以我们传递指向指针的指针。在函数内部,我们使用三个指针 `prev`、`current` 和 `next` 来依次遍历链表,并将每个节点的指针指向前一个节点,从而实现原地逆转链表的目的。 最后,我们定义了一个 `push` 函数来添加新节点到链表的头部,并定义了 `printList` 函数来打印链表中所有节点的值。在 `main` 函数中,我们创建了一个包含三个节点的链表,并调用 `reverseList` 函数来原地逆转该链表,最后打印出原始和逆转后的链表

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值