单链表基础操作及实现

单链表—增删查改

  • 在单链表中增加结点

增加新结点:1.在链表末尾增加(示例代码)

            2.在链表头部增加

            3.在中间某个位置增加

接头体:

//链表结点 结构体

typedef struct Node {

    int data;          //数据域

    struct Node* next; //指针域

}Node;

创建一个带有虚拟头结点的空链表。(初始化)

代码如下:

//创建头结点

Node* Creat() {

    Node* head = (Node*)malloc(sizeof(Node));

    head->next = NULL;

    return head;

}

  1. 在链表尾插入新结点(尾插)
    condition 1:链表为空,直接让该链表指向开辟的结点

condition 2:第二种情况非空,比较复杂,我们通过画图来解决:

代码实现:

//插结点到尾部

void Insert(Node* head, int data) {

    Node *new = (Node*)malloc(sizeof(Node));//分配新的Node结构体对象,将指针值赋值

    new->data = data;//设置数据成员

    new->next = NULL;//表示是最后一个结点



    Node* current = head;

    while (current->next != NULL) { //遍历,直至找到链表最后一个结点

         current = current->next; //指针滑动

    }

    current->next = new; //current指针指向最后一个结点,使current->next成为链表的最后一个结点

}

在链表指定位置插入新结点

【特别注意,不管在什么地方插入数据,我们都要传递二级指针】

当前有链表如下:

例如想在元素4之间插入新结点,过程如下:

  1. 生成新结点
  2. 将新结点下一结点为NULL,表示是最后一个结点
  3. 遍历链表,直到找到指定位置
  4. 插入新结点到指定位置

类似与找到位置,将新结点插入到其中

代码实现如下:

void InsertAtIndex(Node* head, int index, int data) {

    if (index<0) {

         printf("无效的指数\n");

         return;

    }



    Node* new = (Node*)malloc(sizeof(Node));

    new->data = data;

    new->next = NULL;



    Node* current = head;

    int i = 0;//记录遍历链表的索引

    while (i < index && current != NULL)//遍历,直到找到指定位置,然后插入新节点

    {

         current = current->next;//滑动指针

         i++;//记录遍历索引

    }



    if (current == NULL) {  //没找到提醒

         printf("索引超出范围\n");

    }



    new->next = current->next;//将新结点的下一结点设置为当前结点的下一结点,即插入

    current->next = new;  //将当前结点的下一个指针设置为新结点,完成

}

删除结点

特别注意: 和插入数据一样,因为我们删除的可能是链表中的最后一个数据,即可能会改变current的指向(使之指向NULL)所以不管我们在什么地方删除数据,都需要传递二级指针

删除单链表上第i个结点ai:

为了删除单向链表中的某个结点,首先要找到待删除结点的前趋结点,然后将此前趋结点的指针域去指向待删除结点的后继结点(p->next=q->next),最后释放被删除结点所占的存储空间。

  1. 查找第i-1个结点的地址,并使工作指针p指向第i-1个结点的地址;
  2. 将q指向被删除的第i个结点;
  3. 使p的指针域指向被删除结点的直接后继;
  4. 释放被删除的结点的空间;

内存关系:

在删除结点使用free函数释放了结点所占内存。prev->next = current->next; 正确的更新了链表的结构,删除结点之后的链表仍然是有效的链表。

代码示例

//删除结点(头删)

void Delete(Node* head, int data) {

    Node* current = head->next; //将结点指针初始为第一个结点

    Node* prev = head; //将结点指针初始为链表头结点



    while (current != NULL) //遍历,查找需删除的结点

    {

         if (current->data == data) {  //遍历找到位置,执行操作

             prev->next = current->next;//将前一结点的下一结点指针设置为当前结点的下一结点,即删除结点

             free(current);

             return;     

         }

         prev = current;//将当前结点指针更新为下一结点(滑动指针)

         current = current->next;

    }

    printf("没有找到数据%d的节点\n", data);

}

修改单链表结点(调用getNode函数)

原理:

通过getNode函数将查找到数据所在结点,然后将结点所指向的数据更新

循环遍历链表,每次循环将当前指针指向链表下一结点(滑动指针),找到据返回该结点,否则返回NULL指针

代码示例:

//修改单链表数据

void Modify(Node* head, int data, int NewData) {

    Node* current = getNode(head, data);

    if (current != NULL) {

         current->data = NewData;

    }

    else {

         printf("没有找到数据%d的节点\n", data);

    }

}



Node* getNode(Node* head, int data) {

    Node* current = head->next;

    while (current != NULL) {

         if (current->data == data) {

             return current;

         }

         current = current->next;

    }

    return NULL; // 找不到结点

}

查找指定数据的索引位置

采用循环遍历,每次循环将当前结点索引(index)自增,并将当前结点的指针指向下一结点,找到返回索引位置,否则返回-1

代码示例:

//查找位置

int GetIndex(Node* head, int data) {

    Node* current = head->next;//滑动指针

    int index = 0;

    while (current != NULL)

    {

         if (current->data == data) {

             return index;

         }

         index++;

         current = current->next;

    }

    return -1;//找不到结点

}

总结:

注意以下:

1. 内存管理:在对链表进行增删查改操作时,需要动态地分配和释放内存。需要注意内存泄漏和内存碎片的问题,避免造成程序崩溃或性能下降。

2. 边界条件:在对链表进行操作时,需要注意边界条件的处理。例如,在删除节点时,需要考虑当前节点是否为链表的头节点或尾节点;在查找节点时,需要考虑链表是否为空等情况。

3. 链表的遍历:在对链表进行操作时,需要使用循环来遍历链表。需要注意循环的终止条件,避免出现死循环或遍历不完整的情况。

4. 数据的一致性:在对链表进行操作时,需要保证数据的一致性。例如,在删除节点时,需要更新前后节点的指针;在插入节点时,需要更新后续节点的指针等。

对动态内存函数的几大注意:

常见动态内存错误:

 1.对NULL指针的解引用操作

 2.对动态开辟空间的越界访问

 3.对非动态开辟内存使用free释放

 4.使用free释放动态开辟内存的一部分

 5.对同一块动态内存的多次释放

 6.动态开辟内存忘记释放(内存泄漏)

完整代码示例(单链表增删查改)

#include<stdio.h>

#include<stdlib.h>



//链表结点 结构体

typedef struct Node {

    int data;

    struct Node* next;

}Node;



//创建头结点

Node* Creat() {

    Node* head = (Node*)malloc(sizeof(Node));

    head->next = NULL;

    return head;

}



//插结点到尾部

void Insert(Node* head, int data) {

    Node *new = (Node*)malloc(sizeof(Node));

    new->data = data;

    new->next = NULL;



    Node* current = head;

    while (current->next != NULL) {

         current = current->next;

    }

    current->next = new;

}



int getlength(Node* head) {

    Node* current = head;

    int len = 0;

    while (current != NULL)

    {

         len++;

         current = current->next;

    }

    return len;

}



//指定位置插入结点

void InsertAtIndex(Node* head, int index, int data) {

    if (index<0) {

         printf("无效的指数\n");

         return;

    }



    Node* new = (Node*)malloc(sizeof(Node));

    new->data = data;

    new->next = NULL;



    Node* current = head;

    int i = 0;

    while (i < index && current != NULL)

    {

         current = current->next;

         i++;

    }



    if (current == NULL) {

         printf("索引超出范围\n");

    }



    new->next = current->next;

    current->next = new;

}



//删除结点

void Delete(Node* head, int data) {

    Node* current = head->next;

    Node* prev = head;



    while (current != NULL)

    {

         if (current->data == data) {

             prev->next = current->next;

             free(current);

             return;     

         }

         prev = current;

         current = current->next;

    }

    printf("没有找到数据%d的节点\n", data);

}



Node* getNode(Node* head, int data) {

    Node* current = head->next;

    while (current != NULL) {

         if (current->data == data) {

             return current;

         }

         current = current->next;

    }

    return NULL; // 找不到结点

}



//修改单链表数据

void Modify(Node* head, int data, int NewData) {

    Node* current = getNode(head, data);

    if (current != NULL) {

         current->data = NewData;

    }

    else {

         printf("没有找到数据%d的节点\n", data);

    }

}



//查找位置

int GetIndex(Node* head, int data) {

    Node* current = head->next;

    int index = 0;

    while (current != NULL)

    {

         if (current->data == data) {

             return index;

         }

         index++;

         current = current->next;

    }

    return -1;//找不到结点

}



//打印链表

void PrintList(Node* head) {

    Node* current = head->next;

    while (current != NULL)

    {

         printf("%d", current->data);

         current = current->next;

    }

    printf(" \n");

}



int main() {

    //创建空链表

    Node* head = Creat();

    //插入结点

    Insert(head, 10);

    Insert(head, 20);

    Insert(head, 30);

    Insert(head, 40);

    Insert(head, 50);

    //指定位置插入结点

    InsertAtIndex(head, 2, 100);

    //删除

    Delete(head, 30);

    //修改

    Modify(head, 20, 25);

    //打印

    printf("原始链表:\n");

    PrintList(head);

    return 0;

}

代码实现效果

  • 44
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值