数据结构之头节点链表实现-c++实现

 

当涉及到数据结构时,链表是一种非常有用的数据结构,具有许多优点。下面是链表的一些主要优点

1. 动态内存分配:链表使用动态内存分配,这意味着可以根据需要在运行时创建和删除节点,而不需要预先分配固定大小的内存空间。这使得链表在处理不确定数据量或需要频繁插入和删除元素的情况下非常灵活。

2. 灵活性:链表允许在任何位置高效地插入和删除元素,而不会像数组一样需要移动其他元素。只需要修改节点的指针即可完成插入和删除操作,这使得链表在某些场景下比数组更高效。

3. 内存利用率高:链表中的每个节点只需要额外存储一个指向下一个节点的指针,因此链表的内存利用率相对较高,尤其在节点大小较小的情况下。

4. 大小可变:链表的大小可以在运行时动态改变,可以根据需要添加或删除元素。这使得链表非常适合处理未知或不确定的数据量。

5. 不连续的存储空间:链表中的节点在内存中可以分布在不连续的位置,这样可以更容易处理大型数据,而不会出现内存碎片问题。

6. 简化插入和删除操作:相对于数组,在链表中插入和删除元素的操作更简单和高效,特别是当涉及到大量元素移动时。

7. 没有固定大小限制:链表的大小不受限制,可以根据需要增长,只要系统内存足够,链表的长度可以非常长。

主要缺点包括:

1. 随机访问困难:链表中的节点并不是在内存中连续存储的,因此要访问特定位置的节点需要从头节点开始遍历,这导致了链表的随机访问效率较低。

2. 额外的内存消耗:相对于数组,链表每个节点需要额外的指针来指向下一个节点,这会导致一些额外的内存消耗。

3. 不支持随机访问:链表不支持常数时间内的随机访问,必须从头节点开始遍历直到找到所需节点,这可能在某些情况下效率较低。

总体来说,链表是一种非常有用的数据结构,特别适合处理动态、不确定或需要频繁插入和删除操作的数据。在选择使用链表或其他数据结构时,需要根据具体的应用场景和需求来进行权衡。

下面使用visual studio2022实现的链表插入代码:

#include <cstdlib>
#include <stdio.h>

struct Node {
    int data;           // 定义链表节点结构,包含数据和指向下一个节点的指针
    struct Node* next;  // 指向下一个节点的指针
};

struct Node* head;      // 定义链表头节点指针

// 在链表的第n个位置插入节点
void Insert(int data, int n)
{
    // 创建新节点并设置数据
    struct Node* temp1 = new Node();
    temp1->data = data;
    temp1->next = NULL;

    // 插入位置为链表的头部
    if (n == 1)
    {
        temp1->next = head; // 新节点的下一个节点指向原来的头节点
        head = temp1;       // 更新头节点指针为新节点
    }
    else
    {
        // 插入位置不是头部,寻找插入位置的前一个节点
        struct Node* temp2 = new Node();
        temp2 = head;       // 创建一个临时指针指向头节点
        for (int i = 0; i < n - 2; i++) // 遍历找到插入位置的前一个节点
        {
            temp2 = temp2->next;
        }
        temp1->next = temp2->next;  // 新节点的下一个节点指向原来位置的后一个节点
        temp2->next = temp1;        // 前一个节点的下一个节点指向新节点,完成插入操作
    }
}

// 打印链表
void print()
{
    struct Node* temp = head; // 创建一个临时指针指向头节点
    printf("List is: ");
    while (temp != NULL) // 遍历链表并打印节点数据
    {
        printf("%d ", temp->data);
        temp = temp->next; // 移动指针到下一个节点
    }
    printf("\n");
}

int main()
{
    head = NULL; // 初始化头节点指针为空
    Insert(2, 1); // 插入数据2到链表的第1个位置
    Insert(3, 2); // 插入数据3到链表的第2个位置
    Insert(456, 2); // 插入数据456到链表的第2个位置
    Insert(75, 1); // 插入数据75到链表的第1个位置
    print(); // 打印链表
    return 0; // 程序执行完毕,返回0
}

这部分代码主要使用了以下关键方法实现链表插入:

1. `struct Node`:定义了链表节点的结构体,包含一个整数类型的数据成员 `data` 和一个指向下一个节点的指针 `next`。

2. `struct Node* head`:定义了链表的头节点指针,初始值为 `NULL`,表示链表为空。

3. `void Insert(int data, int n)`:这是插入节点的函数,它接收一个整数类型的数据 `data` 和一个整数类型的位置 `n`,用于在链表的第 `n` 个位置插入一个新节点。

4. `void print()`:这是打印链表的函数,用于遍历链表并输出每个节点的数据。

核心代码部分主要是在 `Insert` 函数中的插入操作实现。如果要在链表的第 `n` 个位置插入新节点,需要找到第 `n-1` 个节点,然后将新节点插入到其后面。这个过程主要包括以下几个步骤:

- 创建新节点 `temp1` 并设置数据。
- 如果插入位置为链表头部(`n == 1`),则将新节点的 `next` 指向当前的头节点,然后更新头节点为新节点。
- 如果插入位置不是头部,则需要找到第 `n-1` 个节点。这里使用 `temp2` 临时指针,从头节点开始依次遍历 `n-1` 个节点,找到需要插入的位置。
- 将新节点 `temp1` 的 `next` 指向 `temp2` 节点的下一个节点,然后将 `temp2` 节点的 `next` 指向新节点 `temp1`,完成插入操作。

借鉴意义:

- 这部分代码展示了链表的基本操作,包括创建节点、插入节点和遍历链表。对于初学者来说,这是一个非常好的入门示例,有助于理解链表的基本原理和操作。

- 链表是一种常见的数据结构,具有很多优点,特别适用于频繁插入和删除操作的场景。这个示例展示了链表如何实现动态插入节点,从而展示了链表的灵活性和高效性。

- 在实际编程中,当需要处理动态数据集合时,链表是一个非常有用的选择。了解链表的基本实现原理有助于扩展到更复杂的链表操作和算法。

虽然这部分代码是一个简单的链表示例,但是对于学习数据结构和算法以及理解动态数据集合的处理方式都有很大的借鉴意义。学习链表是理解其他更复杂的数据结构和算法的重要基础

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是使用链表实现基准划分的简单代码: ```c #include <stdio.h> #include <stdlib.h> // 定义节点结构体 typedef struct Node { int data; struct Node *next; } Node, *LinkedList; // 创建链表 LinkedList createLinkedList(int n) { LinkedList head = (LinkedList)malloc(sizeof(Node)); head->next = NULL; LinkedList tail = head; for (int i = 0; i < n; i++) { int value; printf("请输入第%d个节点的值: ", i + 1); scanf("%d", &value); LinkedList node = (LinkedList)malloc(sizeof(Node)); node->data = value; node->next = NULL; tail->next = node; tail = node; } return head; } // 输出链表 void printLinkedList(LinkedList head) { LinkedList curr = head->next; while (curr != NULL) { printf("%d ", curr->data); curr = curr->next; } printf("\n"); } // 拆分链表 LinkedList partitionLinkedList(LinkedList head, int pivot) { // 建立两个链表,一个存放小于基准值的节点,一个存放大于基准值的节点 LinkedList smallHead = (LinkedList)malloc(sizeof(Node)); smallHead->next = NULL; LinkedList smallTail = smallHead; LinkedList largeHead = (LinkedList)malloc(sizeof(Node)); largeHead->next = NULL; LinkedList largeTail = largeHead; // 遍历原链表,将小于基准值的节点放入 small 链表,将大于基准值的节点放入 large 链表 LinkedList curr = head->next; while (curr != NULL) { if (curr->data < pivot) { smallTail->next = curr; smallTail = curr; } else { largeTail->next = curr; largeTail = curr; } curr = curr->next; } // 将 small 链表和 large 链表合并 smallTail->next = largeHead->next; largeTail->next = NULL; // 释放 large 链表节点 free(largeHead); return smallHead; } int main() { int n; printf("请输入链表节点数: "); scanf("%d", &n); LinkedList head = createLinkedList(n); printf("原链表: "); printLinkedList(head); int pivot; printf("请输入基准值: "); scanf("%d", &pivot); LinkedList newHead = partitionLinkedList(head, pivot); printf("拆分后的链表: "); printLinkedList(newHead); // 释放链表内存 LinkedList curr = newHead; while (curr != NULL) { LinkedList temp = curr; curr = curr->next; free(temp); } return 0; } ``` 在这个实现中,我们首先定义了一个节点结构体,包含数据和指向下一个节点的指针。然后,我们使用 createLinkedList 函数创建一个链表。在 createLinkedList 函数中,我们使用了一个 for 循环,提示用户输入每个节点的值,并使用 malloc 函数为每个节点分配内存。我们使用 tail 变量来跟踪链表的尾部,以便我们可以将新节点插入到末尾。 接下来,我们使用 printLinkedList 函数输出链表。 在 partitionLinkedList 函数中,我们创建了两个链表,一个用于存放小于基准值的节点,另一个用于存放大于基准值的节点。我们遍历原链表,将小于基准值的节点放入 small 链表,将大于基准值的节点放入 large 链表。然后,我们将 small 链表和 large 链表合并,并返回 small 链表节点。 在 main 函数中,我们先创建一个链表,然后提示用户输入基准值。接下来,我们使用 partitionLinkedList 函数将链表拆分,并使用 printLinkedList 函数输出拆分后的链表。最后,我们使用 while 循环释放链表内存。 注意,在释放链表内存时,我们必须从 newHead 开始遍历,因为它是我们创建的第一个节点。否则,我们将无法访问整个链表

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值