赞
踩
大家好,我是Abert。
这篇文章和大家分享用C语言实现数据结构中的单链表。
单链表可以看作是“拆分开”的顺序表。在顺序表的基础上,单链表做了一些优化,但同时也丧失了一些顺序表有的功能。
我们一起来学习单链表吧!!!
上图可以看作是单链表的一个简单结构,多个节点链接起来(实际在内存中的存储可能不是这样的一条规则的链)
链表插入数据不会像顺序表一样一次开辟很多空间,插入一个类型的数据,开辟一个节点,通过改变指针的指向来把新数据与原数据串接起来,如下图
同理,单链表删除数据也只需要改变指针的指向的空间,然后free掉要删除的空间。
如下图:
该项目要创建三个文件。
头文件 SLlist.h (存放程序中需要的头文件以及声明实现功能的函数)
源文件 SLlist.c (存放实现程序功能的代码)
源文件 test.c (存放主函数及测试函数功能的代码)
- typedef int SLDataType;
-
- typedef struct SLlistNode
- {
- SLDataType data;//存放数据
- struct SLlistNode* next;//节点
-
- }SLTNode;
这里创建好结构体来成为单链表的子结构,假设创建了一些结构体变量:
SLTNode* n1, *n2, *n3, *n4;
把它们链接起来只需要改变它们内部指针变量的指向。如下:
n1->next = n2;
n2->next = n3;
n3->next = n4;
n4->next = NULL;
如此这些节点会链接起来,就是一个简单的单链表。
这里利用了二级指针,改变结构体指针需要传入该指针的地址,即为二级指针。
下面需要改变头节点的功能皆需要二级指针
(可以不使用二级指针,但必须return 一个 SLTNode* 的头节点指针。)
本文使用二级指针的方式。
- //尾插
- void SLlistPushBack(SLTNode** pphead, SLDataType x)
- {
- assert(pphead);
- SLTNode* newnode = BuySLlistNode(x);
-
- if (*pphead == NULL)
- {
- *pphead = newnode;
- }
- else
- {
- //找尾节点
- SLTNode* tail = *pphead;
- while (tail->next != NULL)
- {
- tail = tail->next;
- }
-
- tail->next = newnode;
- }
-
- }
- //头插
- void SLlistPushFront(SLTNode** pphead, SLDataType x)
- {
- assert(pphead);
-
- SLTNode* newnode = BuySLlistNode(x);
- newnode->next = *pphead;
- *pphead = newnode;
- }
- //尾删
- void SLlistPopBack(SLTNode** pphead)
- {
- assert(pphead);
- assert(*pphead);
-
- //1.只有一个节点
- //2.有多个节点
- if ((*pphead)->next == NULL)
- {
- free(*pphead);
- *pphead = NULL;
- }
- else
- {
- SLTNode* tail = *pphead;
- while (tail->next->next != NULL)
- {
- tail = tail->next;
- }
- free(tail->next);
- tail->next = NULL;
- }
-
- }
- //头删
- void SLlistPopFront(SLTNode** pphead)
- {
- assert(pphead);
- assert(*pphead);
- SLTNode* next = (*pphead)->next;
- free(*pphead);
- *pphead = next;
-
- }
- //查询
- SLTNode* SLlistFind(SLTNode* phead, SLDataType x)
- {
- SLTNode* cur = phead;
- while (cur)
- {
- if (cur->data = x)
- {
- return cur;
- cur = cur->next;
- }
- }
-
- return NULL;
- }
- //在pos位置之前插入
- void SLlistInsert(SLTNode** pphead, SLTNode* pos, SLDataType x)
- {
- assert(pos);
- assert(pphead);
-
- //头插
- if (pos == *pphead)
- {
- SLlistPushFront(pphead, x);
- }
- else
- {
- SLTNode* prev = *pphead;
- while (prev->next != pos)
- {
- prev = prev->next;
- }
-
- SLTNode* newnode = BuySLlistNode(x);
- prev->next = newnode;
- newnode->next = pos;
- }
-
- }
- //删除pos位置的值
- void SLlistErase(SLTNode** pphead, SLTNode* pos)
- {
- assert(pphead);
- assert(pos);
-
- //头删
- if (pos = *pphead)
- {
- SLlistPopFront(pphead);
- }
- else
- {
- SLTNode* prev = *pphead;
- while (prev->next != pos)
- {
- prev = prev->next;
-
- }
- prev->next = pos->next;
-
- free(pos);
- pos = NULL;
- }
-
- }
- //在pos位置之后插入x
- void SLlistInsertAfter(SLTNode** pphead, SLTNode* pos, SLDataType x)
- {
- assert(pos);
-
- SLTNode* newnode = BuySLlistNode(x);
- SLTNode* next = pos->next;
- pos->next = newnode;
- newnode->next = next;
-
- }
- //删除pos之后的值
- void SLlistEraseAfter(SLTNode* pos)
- {
- assert(pos);
-
- if (pos->next == NULL)
- {
- return;
- }
- SLTNode* del = pos->next;
- pos->next = del->next;
-
- free(del);
- del = NULL;
- }
- #pragma once
- #include <stdio.h>
- #include <stdlib.h>
- #include <assert.h>
-
- typedef int SLDataType;
-
- typedef struct SLlistNode
- {
- SLDataType data;
- struct SLlistNode* next;
-
- }SLTNode;
-
- //初始化单链表
- SLTNode* BuySLlistNode(SLDataType x);
-
- //打印单链表
- void SLPrint(SLTNode* phead);
-
- //尾插
- void SLlistPushBack(SLTNode** pphead, SLDataType x);
-
- //头插
- void SLlistPushFront(SLTNode** pphead, SLDataType x);
-
- //尾删
- void SLlistPopBack(SLTNode** pphead);
-
- //头删
- void SLlistPopFront(SLTNode** pphead);
-
- //查询
- SLTNode* SLlistFind(SLTNode* phead, SLDataType x);
-
- //在pos位置之前插入
- void SLlistInsert(SLTNode** pphead, SLTNode* pos, SLDataType x);
-
- //删除pos位置的值
- void SLlistErase(SLTNode** pphead, SLTNode* pos);
-
- //在pos位置之后插入x
- void SLlistInsertAfter(SLTNode** pphead, SLTNode* pos, SLDataType x);
-
- //删除pos之后的值
- void SLlistEraseAfter(SLTNode* pos);
- #define _CRT_SECURE_NO_WARNINGS 1
- #include"SLlist.h"
-
-
- //创建一个节点
- SLTNode* BuySLlistNode(SLDataType x)
- {
- SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
- assert(newnode);
- newnode->data = x;
- newnode->next = NULL;
-
- return newnode;
- }
-
-
- //打印单链表
- void SLPrint(SLTNode* phead)
- {
- SLTNode* cur = phead;
- while (cur != NULL)
- {
- printf("%d->", cur->data);
- cur = cur->next;
- }
- printf("NULL\n");
-
- }
-
-
- //尾插
- void SLlistPushBack(SLTNode** pphead, SLDataType x)
- {
- assert(pphead);
- SLTNode* newnode = BuySLlistNode(x);
-
- if (*pphead == NULL)
- {
- *pphead = newnode;
- }
- else
- {
- //找尾节点
- SLTNode* tail = *pphead;
- while (tail->next != NULL)
- {
- tail = tail->next;
- }
-
- tail->next = newnode;
- }
-
- }
-
-
- //头插
- void SLlistPushFront(SLTNode** pphead, SLDataType x)
- {
- assert(pphead);
-
- SLTNode* newnode = BuySLlistNode(x);
- newnode->next = *pphead;
- *pphead = newnode;
- }
-
-
- //尾删
- void SLlistPopBack(SLTNode** pphead)
- {
- assert(pphead);
- assert(*pphead);
-
- //1.只有一个节点
- //2.有多个节点
- if ((*pphead)->next == NULL)
- {
- free(*pphead);
- *pphead = NULL;
- }
- else
- {
- SLTNode* tail = *pphead;
- while (tail->next->next != NULL)
- {
- tail = tail->next;
- }
- free(tail->next);
- tail->next = NULL;
- }
-
- }
-
-
- //头删
- void SLlistPopFront(SLTNode** pphead)
- {
- assert(pphead);
- assert(*pphead);
- SLTNode* next = (*pphead)->next;
- free(*pphead);
- *pphead = next;
-
- }
-
-
- //查询
- SLTNode* SLlistFind(SLTNode* phead, SLDataType x)
- {
- SLTNode* cur = phead;
- while (cur)
- {
- if (cur->data = x)
- {
- return cur;
- cur = cur->next;
- }
- }
-
- return NULL;
- }
-
-
- //在pos位置之前插入
- void SLlistInsert(SLTNode** pphead, SLTNode* pos, SLDataType x)
- {
- assert(pos);
- assert(pphead);
-
- //头插
- if (pos == *pphead)
- {
- SLlistPushFront(pphead, x);
- }
- else
- {
- SLTNode* prev = *pphead;
- while (prev->next != pos)
- {
- prev = prev->next;
- }
-
- SLTNode* newnode = BuySLlistNode(x);
- prev->next = newnode;
- newnode->next = pos;
- }
-
- }
-
-
- //删除pos位置的值
- void SLlistErase(SLTNode** pphead, SLTNode* pos)
- {
- assert(pphead);
- assert(pos);
-
- //头删
- if (pos = *pphead)
- {
- SLlistPopFront(pphead);
- }
- else
- {
- SLTNode* prev = *pphead;
- while (prev->next != pos)
- {
- prev = prev->next;
-
- }
- prev->next = pos->next;
-
- free(pos);
- pos = NULL;
- }
-
- }
-
-
- //在pos位置之后插入x
- void SLlistInsertAfter(SLTNode** pphead, SLTNode* pos, SLDataType x)
- {
- assert(pos);
-
- SLTNode* newnode = BuySLlistNode(x);
- SLTNode* next = pos->next;
- pos->next = newnode;
- newnode->next = next;
-
- }
-
-
- //删除pos之后的值
- void SLlistEraseAfter(SLTNode* pos)
- {
- assert(pos);
-
- if (pos->next == NULL)
- {
- return;
- }
- SLTNode* del = pos->next;
- pos->next = del->next;
-
- free(del);
- del = NULL;
- }
- #define _CRT_SECURE_NO_WARNINGS 1
- #include"SLlist.h"
-
- //测试尾插
- void TestSList1()
- {
- //struct SListNode*
- SLTNode* n1 = (SLTNode*)malloc(sizeof(SLTNode));
- assert(n1);
- SLTNode* n2 = (SLTNode*)malloc(sizeof(SLTNode));
- assert(n2);
- SLTNode* n3 = (SLTNode*)malloc(sizeof(SLTNode));
- assert(n3);
- SLTNode* n4 = (SLTNode*)malloc(sizeof(SLTNode));
- assert(n4);
-
- n1->data = 1;
- n2->data = 2;
- n3->data = 3;
- n4->data = 4;
-
- n1->next = n2;
- n2->next = n3;
- n3->next = n4;
- n4->next = NULL;
-
- SLTNode* plist = n1;
- SListPrint(plist);
-
- SListPushBack(&plist, 5);
- SListPushBack(&plist, 6);
- SListPushBack(&plist, 7);
- SListPushBack(&plist, 8);
- SListPrint(plist);
- }
-
-
-
- //测试头插
- void TestSList2()
- {
- SLTNode* plist = NULL;
- SListPushFront(&plist, 0);
- SListPushFront(&plist, 1);
- SListPushFront(&plist, 2);
- SListPushFront(&plist, 3);
- SListPushFront(&plist, 4);
- SListPrint(plist);
-
- SListPopFront(&plist);
- SListPopFront(&plist);
- SListPopFront(&plist);
- SListPopFront(&plist);
- SListPopFront(&plist);
- //SListPopFront(&plist);
- SListPrint(plist);
- }
-
-
- //测试尾插与尾删
- void TestSList3()
- {
- SLTNode* plist = NULL;
- SListPushBack(&plist, 1);
- SListPushBack(&plist, 2);
- SListPushBack(&plist, 3);
- SListPushBack(&plist, 4);
-
- SListPrint(plist);
-
- SListPopBack(&plist);
- SListPrint(plist);
-
- SListPopBack(&plist);
- SListPrint(plist);
-
- SListPopBack(&plist);
- SListPrint(plist);
-
- SListPopBack(&plist);
- SListPrint(plist);
-
- //SListPopBack(&plist);
- //SListPrint(plist);
- }
-
-
- //测试查询
- void TestSList4()
- {
- SLTNode* plist = NULL;
- SListPrint(plist);
-
- SListPushBack(&plist, 1);
- SListPushBack(&plist, 2);
- SListPushBack(&plist, 3);
- SListPushBack(&plist, 4);
- SListPrint(plist);
-
- SLTNode* ret = SListFind(plist, 3);
- if (ret)
- {
- printf("找到了\n");
- ret->data = 30;
- }
- SListPrint(plist);
-
-
- SLTNode* pos = SListFind(plist, 4);
- if (pos)
- {
- SListInsert(&plist, pos, 40);
- }
- SListPrint(plist);
-
- //SListPushBack(NULL, 1);
-
- //SListInsert(&plist, NULL, 40);
- //SListPrint(plist);
-
- pos = SListFind(plist, 4);
- if (pos)
- {
- SListErase(&plist, pos);
- }
- SListPrint(plist);
- }
-
- int main()
- {
- //测试哪个模块的功能,只需解引用该模块的函数
-
- /*TestSList1();
- TestSList2();
- TestSList3();*/
- TestSList4();
-
- return 0;
- }
单链表的优点:
单链表中插入一个类型的数据仅需开辟一个结点的空间,空间利用率高。
删除数据只需释放结点的空间,不需要挪动数据。
任意删除或添加数据,时间复杂度尾O(1)
单链表的缺点:
单链表中任意删除/添加/查找/修改的功能不能使用(不支持数据的随机访问)。
单链表相比顺序表有些许提升,但同时也存在一系列问题。
总体来说,需要不断插入删除数据的时候,采用单链表会比顺序表效率高。
以上就是这篇文章的全部内容,希望对大家有帮助。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。