链表是最基本的线性数据结构之一,单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始。
一、单链表的概述
1.单链表的分类
单链表的最大特点是可以将物理地址上不连续的数据连接起来,通过指针来对物理地址进行操作,实现增删改查等功能。
单链表分为两种:无头单链表和有头单链表。
无头单链表:pHead只是一个指针,指向链表的第一个节点。
有头单链表:pHead是链表的头结点,只不过头结点里的data不保存信息。
2.单链表的存储方式
链式存储结构的线性表将采用一组任意的存储单元存放线性表中的数据元素。由于不需要按顺序存储,链表在插入、删除数据元素时比顺序存储要快,但是在查找一个节点时则要比顺序存储要慢。
使用链式存储可以克服顺序线性表需要预先知道数据大小的缺点,链表结构可以充分利用内存空间,实现灵活的内存动态管理。但是链式存储失去了数组随机存取的特点,同时增加了节点的指针域,空间开销较大。
3.单链表的优缺点
链表的优点:
- 插入删除速度快(因为有next指针指向其下一个节点,通过改变指针的指向可以方便的增加删除元素)。
- 内存利用率高,不会浪费内存(可以使用内存中细小的不连续空间(大于node节点的大小),并且在需要空间的时候才创建空间)。
- 大小没有固定,拓展很灵活。
- 不能随机查找,必须从第一个开始遍历,查找效率低。
二、单链表的基本操作
初始化Init
打印Print
头插PushFront 头删PopFront
尾插PushBack 尾删PopBack
查找Find
销毁Destroy
...
三、单链表的实现
无头单链表的实现:
----------------------------------LinkList.h-----------------------------------------
#pragma once
#ifndef __LINKLIST_H__
#define __LINKLIST_H__
#include<assert.h>
#include<stdio.h>
#include<stdlib.h>
typedef int DataType;
typedef struct Node
{
DataType data;
struct Node* next;
}Node,*pNode,List,*pList;
void InitLinkList(pList *pplist);//初始化
void PushBack(pList *pplist,DataType d);//尾插
void PrintLinkList(pList plist);//打印
void DestroyLinkList(pList* pplist);//销毁
int GetListLength(pList plist); //链表长度
void PopBack(pList* pplist);//尾删
void PushFront(pList* pplist, DataType d);//头插
void PopFront(pList* pplist);//头删
pNode Find(pList plist, DataType d);//查找
void Insert(pList* pplist, pNode pos, DataType d);//在指定位置之前插入一个值
void Erase(pList* pplist, pNode pos);//指定位置删除
void Remove(pList* pplist, DataType d);//删除指定元素
void RemoveAll(pList* pplist, DataType d);//删除指定所有元素
void EraseNotTailNode(pNode pos);//删除一个无头单链表的非尾节点
----------------------------------LinkList.c--------------------------------------------
#define _CRT_SECURE_NO_WARNINGS 1
#include"LinkList.h"
void InitLinkList(pList *pplist)//初始化
{
assert(pplist != NULL);
*pplist = NULL;
}
void PrintLinkList(pList plist)//打印
{
pNode cur = plist;
while (cur != NULL)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
void DestroyLinkList(pList* pplist)//销毁
{
pNode cur = *pplist;
assert(pplist != NULL);
while (cur != NULL)
{
pNode del = cur;
cur = cur->next;
free(del);
del = NULL;
}
*pplist = NULL;//空链表
}
pNode BuyNode(DataType d)//创建新节点
{
pNode newNode = (pNode)malloc(sizeof(Node));
if (newNode == NULL)
{
perror("BuyNode : :malloc");
return NULL;
}
newNode->data = d;
newNode->next = NULL;
return newNode;
}
int GetListLength(pList plist) //链表长度
{
pNode cur = plist;
DataType n = 0;
while (cur)
{
n++;
cur = cur->next;
}
return n;
}
void PushBack(pList *pplist, DataType d)//尾插
{
pNode newNode = NULL;
assert(pplist != NULL);
newNode = BuyNode(d);
if (newNode == NULL)
{
return;
}
if (*pplist == NULL)
{
*pplist = newNode;
}//无节点
else
{
pNode cur = *pplist;
while (cur->next != NULL)
{
cur = cur->next;
}
cur->next = newNode;
}//有节点
}
void PopBack(pList* pplist)//尾删
{
pNode del = *pplist;
pNode cur = *pplist;
if (*pplist == NULL)
{
return;
}
while (del->next!=NULL)
{
cur = del;
del = del->next;
}
cur->next = NULL;
free(del);
del = NULL;
}
void PushFront(pList* pplist, DataType d)//头插
{
assert(pplist != NULL);
pNode newNode = NULL;
newNode = BuyNode(d);
newNode->next = *pplist;
*pplist = newNode;
}
void PopFront(pList* pplist)//头删
{
pNode del = *pplist;
*pplist = del->next;
free(del);
del = NULL;
}
pNode Find(pList plist, DataType d) //查找
{
pNode cur = plist;
while (cur != NULL)
{
if (cur->data == d)
{
return cur;
}
cur = cur->next;
}
return cur;
}
void Insert(pList* pplist, pNode pos, DataType d)//插入(插入的位置在pos前,利用Find找到pos)
{
assert(pos != NULL);
assert(pplist != NULL);
if (*pplist == NULL)//空链表
{
return;
}
if (*pplist == pos)//一个节点
{
PushFront(pplist, d);
}
else//两个及以上节点
{
pNode cur = *pplist;
pNode newNode = NULL;
newNode = BuyNode(d);
while (cur && cur->next!= pos)
{
cur = cur->next;
}
if (cur != NULL)
{
newNode->next = cur->next;
cur->next = newNode;
}
}
}
void Erase(pList* pplist, pNode pos)//删除pos
{
assert(pplist != NULL);
assert(pos != NULL);
if (*pplist == NULL)
{
return;
}
if (*pplist == pos)
{
PopFront(pplist);
}
else
{
pNode cur = *pplist;
while (cur && cur->next != pos)
{
cur = cur->next;
}
if (cur != NULL)
{
cur->next = pos->next;
free(pos);
pos = NULL;
}
}
}
void Remove(pList* pplist, DataType d)//删除指定元素
{
assert(pplist != NULL);
pNode cur = *pplist;
pNode pre = NULL;
while (cur)
{
if (cur->data == d)
{
if ((*pplist)->data == d)
{
PopFront(pplist);
}
else
{
pre->next = cur->next;
free(cur);
cur = NULL;
}
return;
}
pre = cur;
cur = cur->next;
}
}
void RemoveAll(pList* pplist, DataType d)//删除指定所有元素
{
assert(pplist != NULL);
pNode cur = *pplist;
pNode pre = NULL;
pNode tmp = NULL;
while (cur)
{
if (cur->data == d)
{
if ((*pplist)->data == d)
{
PopFront(pplist);
}
else
{
tmp = cur;
pre->next = cur->next;
free(tmp);
tmp = NULL;
}
cur = pre;
}
else
{
pre = cur;
cur = cur->next;
}
}
}
void EraseNotTailNode(pNode pos)//删除一个无头单链表的非尾节点
{
pNode del = NULL;
if (pos == NULL || pos->next == NULL)
return;
del = pos->next;
pos->data = del->data;
pos->next = del->next;
free(del);
del = NULL;
}
--------------------------------------test.c-----------------------------------------
#define _CRT_SECURE_NO_WARNINGS 1
#include "LinkList.h"
void test()
{
List* plist = NULL;//指向一条链表的指针
InitLinkList(&plist);
PushBack(&plist, 1);
PushBack(&plist, 2);
PushBack(&plist, 3);
PushBack(&plist, 2);
PushBack(&plist, 4);
//int i = GetListLength(plist);
//printf("链表长度为:%d\n", i);
//PopBack(&plist);
//PrintLinkList(plist);
//PushFront(&plist, 5);
//PrintLinkList(plist);
//PopFront(&plist);
//PrintLinkList(plist);
//Remove(&plist, 2);
//PrintLinkList(plist);
/*pNode to_insert = Find(plist, 3);
Insert(&plist, to_insert, 5);
PrintLinkList(plist);*/
/*pNode to_erase = Find(plist, 5);
Erase(&plist, to_erase);
PrintLinkList(plist);*/
//pNode to_erase_NTN = Find(plist, 3);
//EraseNotTailNode(to_erase_NTN);
//PrintLinkList(plist);
RemoveAll(&plist, 2);
PrintLinkList(plist);
DestroyLinkList(&plist);
}
int main()
{
test();
system("pause");
return 0;
}
有头单链表的实现:
----------------------------------List.h---------------------------------------------
#pragma once
#ifndef __LIST_H__
#define __LIST_H__
#include<assert.h>
#include<stdio.h>
#include<stdlib.h>
typedef int DataType;
typedef struct SHListNode
{
DataType data;
struct SHListNode* next;
}Node;
void InitSHListNode(Node** pHead);//初始化
void SHListPushBack(Node* pHead, DataType data);//尾插
void SHListPopBack(Node* pHead);//尾删
void SHListPushFront(Node* pHead, DataType data);//头插
void SHListPopFront(Node* pHead);//头删
void PrintLinkList(Node* pHead);//打印
void DestroySHList(Node** pHead);//销毁
---------------------------------List.c------------------------------------------------
#define _CRT_SECURE_NO_WARNINGS 1
#include "List.h"
Node* BuySHListNode(DataType data)//创建新结点
{
Node* pNewNode = (Node*)malloc(sizeof(Node));
if (NULL == pNewNode)
{
assert(0);
return NULL;
}
pNewNode->data = data;
pNewNode->next = NULL;
return pNewNode;
}
void InitSHListNode(Node** pHead)//初始化
{
assert(pHead);
*pHead = BuySHListNode(0);
}
void SHListPushBack(Node* pHead, DataType data)//尾插
{
Node* pNewNode = NULL;
pNewNode = BuySHListNode(data);
assert(pHead);
Node* pCur = NULL;
pCur = pHead;
while (pCur->next != NULL)
{
pCur = pCur->next;
}
pCur->next = pNewNode;
}
void SHListPopBack(Node* pHead)//尾删
{
Node* pCur = pHead;
Node* pPre = NULL;
assert(pHead);
if (NULL == pHead->next)
return;
while (pCur->next)
{
pPre = pCur;
pCur = pCur->next;
}
free(pCur);
pPre->next = NULL;
}
void SHListPushFront(Node* pHead,DataType data)//头插
{
assert(pHead);
Node* pNewNode = NULL;
pNewNode = BuySHListNode(data);
pNewNode->next = pHead->next;
pHead->next = pNewNode;
}
void SHListPopFront(Node* pHead) //尾插
{
assert(pHead);
Node* pDel = NULL;
if (NULL == pHead->next)
return;
pDel = pHead->next;
pHead->next = pDel->next;
free(pDel);
}
void PrintLinkList(Node* pHead) //打印
{
assert(pHead);
Node* pCur = pHead;
while (pCur)
{
printf("%d->", pCur->data);
pCur = pCur->next;
}
printf("NULL\n");
}
void DestroySHList(Node** pHead)//销毁
{
Node* pCur = *pHead;
assert(pHead != NULL);
while (pCur != NULL)
{
Node* pDel = pCur;
pCur = pCur->next;
free(pDel);
pDel = NULL;
}
*pHead = NULL;//空链表
}
--------------------------------------test.c--------------------------------------
#define _CRT_SECURE_NO_WARNINGS 1
#include "List.h"
void test()
{
Node* pHead = NULL;
InitSHListNode(&pHead);
SHListPushBack(pHead, 1);
SHListPushBack(pHead, 2);
SHListPushBack(pHead, 3);
SHListPushBack(pHead, 4);
PrintLinkList(pHead);
SHListPopBack(pHead);
PrintLinkList(pHead);
SHListPushFront(pHead, 3);
PrintLinkList(pHead);
SHListPopFront(pHead);
PrintLinkList(pHead);
DestroySHList(&pHead);
}
int main()
{
test();
system("pause");
return 0;
}