单链表:单向链表是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始。链式存储结构的线性表将采用一组任意的存储单元存放线性表中的数据元素。由于不需要按顺序存储,链表在插入、删除数据元素时比顺序存储要快,但是在查找一个节点时则要比顺序存储要慢。使用链式存储可以克服顺序线性表需要预先知道数据大小的缺点,链表结构可以充分利用内存空间,实现灵活的内存动态管理。但是链式存储失去了数组随机存取的特点,同时增加了节点的指针域,空间开销较大。
下图就是一般形式的单链表
其中data域用来存放数据,next域用来存放指向下一个链表的指针。
单链表分为两种:
(1)不带头节点的链表:此种链表的head即保存第一个数据,访问时从head开始。不利于删除或者添加指定位置数据的操作。
(2)带头节点的链表:此种链表保存数据是从head->next开始的,head中并未保存有数据,访问时自然head->next开始,优点就是方便操作。
头结点:
为了方便满足插入和删除基本操作,我们在链表的头部加入一个“头结点”,如果没有头结点,第一个结点的插入和删除操作跟其他结点不同,需要单独分析,为了省去这个麻烦,因此我们定义了一个头结点,头结点的类型与数据结点一致,标识链表的头指针变量L中存放该结点的地址,这样即使是空表,头指针变量L也不为空了。头结点的加入使得“第一个结点”的问题不存在了,也使得处理“空表”和“非空表”的操作变的一致。头结点的加入纯粹是为了使运算方便,它的数据域即data是没有定义的,指针域中存放的是第一个数 据结点的地址,空表时,指针域为NULL
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef struct Node //一个链表结构体,存放数据等。
{
int data;
struct Node *next;
}Node, *List;
//初始化
void InitList(List list)
{
assert(list != nullptr);
list->next = nullptr;
}
//创建一个新的节点
Node *GetNode(int val) //返回值为Node*
{
Node *Get = (Node*)malloc(sizeof(Node));
assert(Get != nullptr);
Get->data = val;
Get->next = nullptr;
return Get;
}
//链表的头插法
bool headInsert(List list, int val)
{
assert(list != nullptr);
Node* cur = GetNode(val);
cur->next = list->next;
list->next = cur;
return true;
}
//尾插法
bool tailInsert(List list, int val)
{
assert(list != nullptr);
Node *cur = list;
while (cur->next != nullptr) //err
{
cur = cur->next;
}
Node* get = GetNode(val);
cur->next = get;
return true;
}
//是否为空
bool isEmpty(List list)
{
if (list == nullptr || list->next == nullptr)
{
return true;
}
return false;
}
//查找val是否存在,如果存在返回前驱,不存在返回false
Node* Find(List list, int val)
{
assert(list != nullptr);
Node *cur = list;
while (cur->next != nullptr)
{
if (cur->next->data == val)
{
//printf("%d存在\n",val);
return cur;
}
cur = cur->next;
}
//printf("%d unexist\n",val);
return nullptr;
}
//删除单链表中val的节点
bool Delete(List list, int val)
{
Node *p = Find(list, val);
if (p == nullptr)
{
return false;
}
Node *pdel = p->next;
p->next = pdel->next;
free(pdel);
pdel = NULL;
return true;
}
//单链表长度
int length(List list)
{
assert(list != nullptr);
Node *cur = list->next;
int count = 0;
while (cur != nullptr)
{
cur = cur->next;
count++;
}
return count;
}
//pos位置插入
bool Insert(List list, int pos,int val)
{
if (pos<0 || pos>length(list))
{
return false;
}
Node *cur = list;
for (int i = 0; i < pos; ++i)
{
cur = cur->next;
}
Node *pGet = GetNode(val);
pGet->next = cur->next;
cur->next = pGet;
return true;
}
//打印单链表
void Show(List list)
{
Node *pCur = list->next;
while (pCur != NULL)
{
printf("%d ", pCur->data);
pCur = pCur->next;
}
printf("\n");
}
//摧毁
void Destory(List list)
{
Node *del = nullptr;
while (list->next != nullptr)
{
del = list->next;
list->next = del->next;
free(del);
}
del = nullptr;
}
test
int main()
{
Node head;//头结点
InitList(&head);
for (int i = 0; i < 10; i++)
{
headInsert(&head, i);
}
Insert(&head, 3, 99);
Show(&head);
Delete(&head, 5);
Show(&head);
int len = length(&head);
printf("len == %d\n", len);
Destory(&head);
return 0;
}