各人好,这里是小编的博客频道
小编的博客:就爱学编程
很高兴在CSDN这个各人庭与各人相识,希望能在这里与各人共同进步,共同劳绩更好的本身!!!
引言
在C语言中,数据布局的掌握对于高效编程至关重要。此中,单链表作为一种底子且常用的数据布局,具有独特的上风和应用场景。下面将对单链表进行具体介绍,并概述实在现方法。一起来看看吧!!!
那接下来就让我们开始遨游在知识的海洋!
正文
一、单链表的概念与布局
- 单链表(Singly Linked List)是链式存取的数据布局的一种,它用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以节点(Node)来表示的,每个节点包含两部分:数据域和[指针域。数据域用于存储数据元素,而指针域则用于指向下一个节点的地址。末了一个节点的指针域指向NULL,表示链表的末了。
具体来说,单链表的布局可以定义如下:
-
- typedef int SLLDataType; // 单链表存贮的数据类型
- typedef struct SLLNode {
- SLLDataType data; // 数据域
- struct SLLNode* next; // 指针域,指向下一个节点的地址
- } Node;
-
复制代码 二、单链表的上风与应用
相较于顺序表(即数组),单链表具有以下上风:
插入和删除操作高效:在顺序表中插入或删除数据需要移动大量元素,而在单链表中,只需改变相关节点的指针域即可,时间复杂度较低。
动态分配内存:单链表可以根据需要动态申请或开释内存空间,避免了顺序表因巨细固定而造成的内存浪费或不敷标题。
灵活性强:单链表适用于各种复杂的数据处理场景,如循环链表、双向链表等都是由单链演出变而来的。
- 单链表广泛应用于各种数据处理场景中,如实现队列、栈等抽象数据类型,以及办理图论、排序等标题。
三、单链表的实现概述
单链表的实现主要包括以下几个关键步骤:
在C语言中,单链表是一种常见的数据布局,它由一系列节点(Node)组成,每个节点包含数据部分和指向下一个节点的指针。下面我将具体讲解怎样用C语言实现单链表的关键部分,包括节点定义、创建链表、插入节点、删除节点以及遍历链表等操作。
1. 定义节点布局
首先,我们需要定义一个布局体来表示链表的节点:
- #include <stdio.h>
- #include <stdlib.h>
- // 定义节点结构
- typedef struct Node {
- int data; // 数据域
- struct Node* next; // 指针域,指向下一个节点
- } Node;
复制代码 2. 创建链表
创建一个空链表通常意味着初始化一个头指针为NULL:
- Node* createList() {
- return NULL; // 空链表的头指针为NULL
- }
复制代码 3. 在链表头部插入节点
在链表头部插入一个新节点是一个常见的操作。我们首先需要为新节点分配内存,然后设置其数据和指针,末了更新头指针。
- void insertAtHead(Node** head, int newData) {
- // 为新节点分配内存
- Node* newNode = (Node*)malloc(sizeof(Node));
- if (!newNode) {
- printf("Memory allocation error
- ");
- return;
- }
- // 设置新节点的数据
- newNode->data = newData;
- // 将新节点的next指针指向当前的头节点
- newNode->next = *head;
- // 更新头指针
- *head = newNode;
- }
复制代码 4. 删除指定值的节点
删除指定值的节点需要遍历链表并找到目标节点的前一个节点,然后修改前一个节点的next指针以跳过目标节点。同时,别忘了开释被删除节点的内存。
- void deleteNode(Node** head, int key) {
- // 存储临时头指针,用于处理头节点被删除的情况
- Node* temp = *head;
- Node* prev = NULL;
- // 如果头节点就是要删除的节点
- if (temp != NULL && temp->data == key) {
- *head = temp->next; // 改变头指针
- free(temp); // 释放旧头节点
- return;
- }
- // 查找要删除的节点,保持对前一个节点的引用
- while (temp != NULL && temp->data != key) {
- prev = temp;
- temp = temp->next;
- }
- // 如果没有找到该值的节点
- if (temp == NULL) return;
- // 从链表中断开节点,并释放内存
- prev->next = temp->next;
- free(temp);
- }
复制代码 5. 遍历链表
遍历链表意味着重新节点开始,依次访问每一个节点直到碰到NULL指针。
- void printList(Node* node) {
- while (node != NULL) {
- printf("%d -> ", node->data);
- node = node->next;
- }
- printf("NULL
- ");
- }
复制代码 6. 主函数示例
以下是一个简单的主函数示例,展示了怎样使用上述函数来操作单链表:
- int main() {
- Node* head = createList();
- insertAtHead(&head, 1);
- insertAtHead(&head, 2);
- insertAtHead(&head, 3);
- printf("Created linked list: ");
- printList(head);
- deleteNode(&head, 2);
- printf("
- Linked list after deleting 2: ");
- printList(head);
- return 0;
- }
复制代码 总结
- 以上代码展示了怎样在C语言中实现和操作一个简单的单链表。关键部分包括节点布局的定义、链表的创建、节点的插入与删除以及链表的遍历。这些基本操作是单链表实现的底子,也是理解和扩展更复杂数据布局的重要步骤。
四、源码
注意:这是小编本身写的,可能有不敷之处,仅供参考!!!
(1)SLT.h
- #include<stdio.h>
- #include<stdlib.h>
- #include<assert.h>
- typedef int SLTDateType;
- typedef struct SListNode
- {
- SLTDateType data;
- struct SListNode* next;
- }SListNode;
- // 动态申请一个节点
- SListNode* BuySListNode(SLTDateType x);
- // 单链表打印
- void SListPrint(SListNode* plist);
- // 单链表尾插
- void SListPushBack(SListNode** pplist, SLTDateType x);
- // 单链表的头插
- void SListPushFront(SListNode** pplist, SLTDateType x);
- // 单链表的尾删
- void SListPopBack(SListNode** pplist);
- // 单链表头删
- void SListPopFront(SListNode** pplist);
- // 单链表查找
- SListNode* SListFind(SListNode* plist, SLTDateType x);
- // 单链表在pos位置之后插入x
- // 分析思考为什么不在pos位置之前插入?
- void SListInsertAfter(SListNode* pos, SLTDateType x);
- // 单链表删除pos位置之后的值
- // 分析思考为什么不删除pos位置?
- void SListEraseAfter(SListNode* pos);
- // 在pos的前面插入
- void SLTInsert(SListNode** pphead, SListNode* pos, SLTDateType x);
- // 删除pos位置
- void SLTErase(SListNode** pphead, SListNode* pos);
- //销毁链表
- void SLTDestroy(SListNode** pphead);
复制代码 (2)SLT.c
- #include"SLT.h"
- // 动态申请一个节点
- SListNode* BuySListNode(SLTDateType x) {
- SListNode* ptr = (SListNode*)malloc(sizeof(SListNode));
- if (ptr == NULL) {
- return NULL;
- }
- ptr->data = x;
- ptr->next = NULL;
- return ptr;
- }
- // 单链表打印
- void SListPrint(SListNode* plist) {
- SListNode* cur = plist;
- while (cur) {
- printf("%d->", cur->data);
- cur = cur->next;
- }
- printf("NULL");
- printf("\n");
- }
- // 单链表的头插
- void SListPushFront(SListNode** pplist, SLTDateType x)
- {
- SListNode* newnode = BuySListNode(x);
- newnode->next = *pplist;
- *pplist = newnode;
- }
- // 单链表尾插
- void SListPushBack(SListNode** pplist, SLTDateType x) {
- assert(pplist);
- if (NULL == *pplist) {
- SListPushFront(pplist, x);
- return;
- }
- SListNode* newnode = BuySListNode(x);
- SListNode* fail = *pplist;
- while (fail->next) {
- fail = fail->next;
- }
- fail->next = newnode;
- }
- // 单链表的尾删
- void SListPopBack(SListNode** pplist) {
- //一个节点和多个节点
- assert(pplist && *pplist);
- //一个节点
- if ((*pplist)->next == NULL) {
- free(*pplist);
- *pplist = NULL;
- }
- //多个节点
- SListNode* fail = *pplist;
- SListNode* perv = *pplist;
- while (fail->next) {
- perv = fail;
- fail = fail->next;
- }
- free(fail);
- //fail = NULL; //这一步不会把删除后的最后一个节点的next指针改为NULL,这就要对于变量赋值和改值要有理解。
- perv->next = NULL;
- }
- // 单链表头删
- void SListPopFront(SListNode** pplist) {
- assert(pplist && *pplist);
- SListNode* cur = *pplist;
- *pplist = cur->next;
- free(cur);
- }
- // 单链表查找
- SListNode* SListFind(SListNode* plist, SLTDateType x) {
- assert(plist);
- SListNode* cur = plist;
- while (cur) {
- if (cur->data == x)
- return cur;
- }
- printf("找不到\n");
- return NULL;
- }
- // 单链表在pos位置之后插入x
- // 分析思考为什么不在pos位置之前插入?
- void SListInsertAfter(SListNode* pos, SLTDateType x) {
- assert(pos);
- SListNode* cur = BuySListNode(x);
- cur->next = pos->next;
- pos->next = cur;
- }
- // 单链表删除pos位置之后的值
- // 分析思考为什么不删除pos位置?
- void SListEraseAfter(SListNode* pos) {
- assert(pos && pos->next);
- SListNode* temp = pos->next->next;
- free(pos->next);
- pos->next = temp;
- }
- // 在pos的前面插入
- void SLTInsert(SListNode** pphead, SListNode* pos, SLTDateType x) {
- assert(pphead && *pphead);
- SListNode* ptr = BuySListNode(x);
- SListNode* cur = *pphead;
- if (cur == pos) {
- SListPushFront(pphead, x);
- return;
- }
- while (cur->next != pos && cur->next) {
- cur = cur->next;
- }
- if(cur->next == pos){
- cur->next = ptr;
- ptr->next = pos;
- return;
- }
- else assert(cur->next);
- }
-
- // 删除pos位置
- void SLTErase(SListNode** pphead, SListNode* pos) {
- assert(pphead && *pphead);
- if (*pphead == pos) {
- SListPopFront(pphead);
- return;
- }
- SListNode* cur = *pphead;
- while (cur->next != pos && cur->next) {
- cur = cur->next;
- }
- assert(cur->next);
- cur->next = pos->next;
- free(pos);
- }
- //销毁链表
- void SLTDestroy(SListNode** pphead) {
- SListNode* cur = *pphead;
- while (cur) {
- SListNode* temp = cur->next;
- free(cur);
- cur = temp;
- }
- *pphead = NULL;
- }
复制代码 (3)Test.c
- #include"SLT.h"
- void test3() {
- SListNode* n1 = BuySListNode(1);
- SListNode* n2 = BuySListNode(2);
- n1->next = n2;
- n2->next = NULL;
- SListInsertAfter(n1, 3);
- SListInsertAfter(n2, 4);
- SListPrint(n1);
- SListEraseAfter(n1);
- SListEraseAfter(n2);
- SListPrint(n1);
- SLTInsert(&n1, n2, 5);
- SListPrint(n1);
- SLTErase(&n1, n2);
- SListPrint(n1);
- /*SLTErase(&n1, n1);
- SListPrint(n1);*/
- SLTDestroy(&n1);
- }
- void test2() {
- SListNode* n1 = BuySListNode(1);
- SListNode* n2 = BuySListNode(2);
- n1->next = n2;
- n2->next = NULL;
- SListPushBack(&n1, 3);
- SListPushBack(&n1, 4);
- SListPrint(n1);
- SListPopBack(&n1);
- SListPopBack(&n1);
- SListPrint(n1);
- SListPopFront(&n1);
- SListPrint(n1);
- SLTDestroy(&n1);
- }
- void test1() {
- SListNode* n1 = BuySListNode(1);
- SListNode* n2 = BuySListNode(2);
- n1->next = n2;
- n2->next = NULL;
- SListPrint(n1);
- SLTDestroy(&n1);
- }
- int main() {
- test3();
- return 0;
- }
复制代码 快乐的时光总是短暂,咱们下篇博文再见啦!!!不要忘了,给小编点点赞和收藏支持一下,在此非常感谢!!!
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |