一、链表基本概念
1、链表的分类(8种)
- 单向 | 双向
- 有头 | 没有头
- 有循环 | 无循环
- 可随机组合
2、顺序表与链表的区别
3、相关接口介绍
接口 | 功能 |
---|---|
void SListInit(SList* plist) | 初始化链表 |
void SListDstory(SList* plist) | 销毁链表 |
SListNode* BuySListNode(SLTDataType x) | 创建一个链表节点 |
void SListPushFront(SList* plist, SLTDataType x) | 头插 |
void SListPushBack(SList* plist,SLTDataType x) | 尾插 |
void SListPopFront(SList* plist) | 头删 |
void SListPopBack(SList* plist) | 尾删 |
SListNode* SListFind(SList* plist, SLTDataType x) | 在链表中查找一个节点 |
void SListInsertAfter(SListNode* pos, SLTDataType x) | 在链表pos位置后进行插入 |
void SListEraseAfter(SListNode* pos) | 删除链表pos位置之后的节点 |
void SListRemove(SList* plist, SLTDataType x) | 根据x的值删除链表中的节点 |
void SListPrint(SList* plist) | 打印链表元素 |
void Listtest1() | 特殊链表相关接口 |
4、相关接口的具体实现
1.【创建链表结构体】
- 定义一个链表结构体,一共存放两个成员
- 一个存放数据域
- 一个存放指针域(即指向下一个节点的指针)
typedef int SLTDataType;
typedef struct SListNode
{
SLTDataType _data;
struct SListNode* _next;
}SListNode;
2.【初始化链表】
- 初始化链表的思想很简单,只需要让链表中的头结点指向空即可,以防成为野指针
void SListInit(SList* plist)
{
assert(plist);
plist->_head = NULL;
}
3.【销毁链表】
- 销毁链表的思想是,遍历整个链表,将节点逐个释放,再将头结点置空
void SListDstory(SList* plist)
{
assert(plist);
SListNode* cur = plist->_head;
while (cur != NULL)
{
SListNode* next = cur->_next;
free(cur);//释放节点动态开辟的空间
cur = next;
}
plist->_head = NULL;
}
4.【打印链表元素】
- 思路很简单,遍历链表将每个节点中的数据逐个打印即可
void SListPrint(SList* plist)
{
assert(plist);
SListNode* cur = plist->_head;
while (cur != NULL)
{
printf("%d->", cur->_data);
cur = cur->_next;
}
printf("NULL");
}
5.【创建链表节点】
- 我们知道链表和顺序表不一样,链表不需要考虑增容的问题,需要插入元素只要开辟一个节点进行插入即可,因此我们需要单独写一个函数进行节点的创建
- 我们这里的节点是动态开辟的,开辟节点之后,将值赋为x,并让节点的下一个节点指针置空,最后返回这个节点。
SListNode* BuySListNode(SLTDataType x)
{
SListNode* pnode;
pnode = (SListNode*)malloc(sizeof(SListNode));
pnode->_data = x;
pnode->_next = NULL;
return pnode;
}
6、【头插】
- 头插思想比较简单,因为我们创建了一个头结点,这里我们只需要申请一个新的节点,让它指向_head节点,再让它成为_head就完成了头插
void SListPushFront(SList* plist, SLTDataType x)
{
assert(plist);
SListNode* newnode = BuySListNode(x);
newnode->_next = plist->_head;
plist->_head = newnode;
}
7、【尾插】
void SListPushBack(SList* plist, SLTDataType x)
{
assert(plist);
if (plist->_head == NULL)
{
SListNode* newnode = BuySListNode(x);
}
else
{
SListNode* tail = plist->_head;
while (tail->_next != NULL)
{
tail = tail->_next;
}
SListNode* newtail = BuySListNode(x);
tail->_next = newtail;
}
}
8.【头删】
- 思路很简单,其实链表最大的优势就在于它的头插头删,不仅思路简单而且时间复杂度为O(1)
- 记录_head的下一个节点,释放_head节点,让next成为_head节点
void SListPopFront(SList* plist)
{
assert(plist);
SListNode* next = plist->_head->_next;
free(plist->_head);
plist->_head = next;
}
9.【尾删】
void SListPopBack(SList* plist)
{
if (plist->_head->_next == NULL)
{
free(plist->_head);
plist->_head = NULL;
}
else
{
SListNode* prev = NULL;
SListNode* tail = plist->_head;
while (tail->_next != NULL)
{
prev = tail;
tail = tail->_next;
}
free(tail);
prev->_next = NULL;
}
}
10.【查找链表中的元素】
- 遍历链表查找值为x的节点,找到返回该节点指针
- 没找到返回空
SListNode* SListFind(SList* plist, SLTDataType x)
{
assert(plist);
SListNode* cur = plist->_head;
while (cur->_next != NULL)
{
if (cur->_data == x)
return cur;
else
cur = cur->_next;
}
return cur;
}
11、【在pos后插入元素】
- 利用Find找到对应的位置,在pos之后插入元素
// 在pos的后面进行插入
void SListInsertAfter(SListNode* pos, SLTDataType x)
{
assert(pos);
SListNode* newnode = BuySListNode(x);
assert(newnode);
newnode->_next = pos->_next;
pos->_next = newnode;
}
12.【删除pos之后的元素】
- 思路很简单,记录pos的下一个节点和pos的下下一个节点,让pos的_next指向nextnext,再释放next节点即可。
void SListEraseAfter(SListNode* pos)
{
assert(pos && pos->_next);
SListNode* next = pos->_next;
SListNode* nextnext = next->_next;
pos->_next = nextnext;
free(next);
}
无头单向不循环链表完整代码
单链表相关接口介绍List.h
#define _CRT_SECURE_NO_WARNINGS
#ifndef __LIST_H__
#define __LIST_H__
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
typedef int SLTDataType;
typedef struct SListNode
{
SLTDataType _data;
struct SListNode* _next;
}SListNode;
typedef struct SList
{
SListNode* _head;
}SList;
void SListInit(SList* plist);
void SListDstory(SList* plist);
SListNode* BuySListNode(SLTDataType x);
void SListPushFront(SList* plist, SLTDataType x);
void SListPushBack(SList* plist,SLTDataType x);
void SListPopFront(SList* plist);
void SListPopBack(SList* plist);
SListNode* SListFind(SList* plist, SLTDataType x);
// 在pos的后面进行插入
void SListInsertAfter(SListNode* pos, SLTDataType x);
// 在pos的前面进行插入
void SListEraseAfter(SListNode* pos);
void SListRemove(SList* plist, SLTDataType x);
void SListPrint(SList* plist);
void TestSList();
void SListPopFront(SList* plist);
SListNode* SListFind(SList* plist, SLTDataType x);
// 在pos的后面进行插入
void SListInsertAfter(SListNode* pos, SLTDataType x);
void SListEraseAfter(SListNode* pos);
void SListRemove(SList* plist, SLTDataType x);
void SListPrint(SList* plist);
void Listtest1();
#endif //__LIST_H__
单链表相关接口的实现List.c
#include"List.h"
void SListInit(SList* plist)
{
assert(plist);
plist->_head = NULL;
}
void SListDstory(SList* plist)
{
assert(plist);
SListNode* cur = plist->_head;
while (cur != NULL)
{
SListNode* next = cur->_next;
free(cur);
cur = next;
}
plist->_head = NULL;
}
void SListPrint(SList* plist)
{
assert(plist);
SListNode* cur = plist->_head;
while (cur != NULL)
{
printf("%d->", cur->_data);
cur = cur->_next;
}
printf("NULL");
}
SListNode* BuySListNode(SLTDataType x)
{
SListNode* pnode;
pnode = (SListNode*)malloc(sizeof(SListNode));
pnode->_data = x;
pnode->_next = NULL;
return pnode;
}
void SListPushFront(SList* plist, SLTDataType x)
{
assert(plist);
SListNode* newnode = BuySListNode(x);
newnode->_next = plist->_head;
plist->_head = newnode;
}
void SListPushBack(SList* plist, SLTDataType x)
{
assert(plist);
if (plist->_head == NULL)
{
SListNode* newnode = BuySListNode(x);
}
else
{
SListNode* tail = plist->_head;
while (tail->_next != NULL)
{
tail = tail->_next;
}
SListNode* newtail = BuySListNode(x);
tail->_next = newtail;
}
}
void SListPopFront(SList* plist)
{
assert(plist);
SListNode* next = plist->_head->_next;
free(plist->_head);
plist->_head = next;
}
void SListPopBack(SList* plist)
{
if (plist->_head->_next == NULL)
{
free(plist->_head);
plist->_head = NULL;
}
else
{
SListNode* prev = NULL;
SListNode* tail = plist->_head;
while (tail->_next != NULL)
{
prev = tail;
tail = tail->_next;
}
free(tail);
prev->_next = NULL;
}
}
SListNode* SListFind(SList* plist, SLTDataType x)
{
assert(plist);
SListNode* cur = plist->_head;
while (cur->_next != NULL)
{
if (cur->_data == x)
return cur;
else
cur = cur->_next;
}
return cur;
}
// 在pos的后面进行插入
void SListInsertAfter(SListNode* pos, SLTDataType x)
{
assert(pos);
SListNode* newnode = BuySListNode(x);
assert(newnode);
newnode->_next = pos->_next;
pos->_next = newnode;
}
// 在pos的前面进行插入
void SListEraseAfter(SListNode* pos)
{
assert(pos && pos->_next);
SListNode* next = pos->_next;
SListNode* nextnext = next->_next;
pos->_next = nextnext;
free(next);
}
void SListRemove(SList* plist, SLTDataType x)
{
assert(plist);
if (plist->_head->_next==NULL)
{
if (plist->_head->_data == x)
SListPopFront(plist);
else
printf("所删除的数不存在!\n");
}
else
{
SListNode* cur = plist->_head;
SListNode* prev = plist->_head;
while (cur->_next != NULL)
{
if (cur->_data == x)
{
prev->_next = cur->_next;
}
else
{
cur = cur->_next;
prev = prev->_next;
}
}
}
}
void Listtest1()
{
SList list;
SListInit(&list);
//SListPrint(&list);
SListPushFront(&list, 1);
SListPushFront(&list, 2);
SListPushFront(&list, 3);
SListPushFront(&list, 4);
//SListPushBack(&list, 0);
//SListPopFront(&list);
//SListPopBack(&list);
/*SListNode* pos = SListFind(&list, 3);
printf("%d\n", pos->_data);
SListInsertAfter(pos, 6);
SListEraseAfter(pos);*/
SListRemove(&list, 2);
SListPrint(&list);
SListDstory(&list);
}