文章目录
1.链表基本结构
链表由一个个的节点连接成,这里的节点是一个结构体,由数据域与指针域组成。
typedef int SListDateType
typedef struct SListNode
{
SListDataType data;//data变量用来存储数据
struct SListNode* next;//next指向下一个节点;
}SListNode;
//用SListNode重新声明节点类型
不同与顺序表,链表中节点的储存不是连续的,每个节点都是分散的,通过next指针来寻找下一个节点。
链表中的尾节点的next指向NULL,并且还有一个头指针phead指向链表中第一个节点。头指针为空,说明链表是空的。
2.链表的尾插
分两种情况
1.链表为空
2.链表不为空
1.创建一个新的节点,使其指针域指向NULL,数据域放入要放的数据。最后让头指针指向该节点。
2。链表不为空时,同样也要创建一个节点。接着找到尾指针(指针域为空的节点),使其指向新的节点。
先封装创建新节点的函数
SListNode* CreatSListNode(SListDataType x)
{
SListNode* newNode = (SListNode*)malloc(sizeof(SListNode));
if (newNode == NULL)
{
printf("申请空间失败\n:);
return 0;
}
else
{
newNode->next = NULL;
newNode->data = x;
}
return newNode;
}
创建新节点并将其数据域填入数据,之后要找到尾节点(创建一个指针cur,cur最初指向首节点,如果cur的next所指向的指针不为空,cur要继续往后走,知道cur的next指向了NULL,说明cur当前指向的是尾节点),将尾节点的指针指向新节点。
当链表为空时,将头指针指向新节点,需要把头指针的值从NULL改成新节点的地址,所以这里要传址操作。
分成两种情况
void SListPushBack(SListNode** pphead,SListData x)
{
SListNode* newNode = CreatSListNode(x);
if (*pphead == NULL)
{
*phead = newNode;
return;
}
else
{
SListNode* cur = *phead;
while (cur->next != NULL)
cur = cur->next;
cur->next = newNode;
}
3.链表的尾删
删除链表的尾节点,同样也要找到尾节点的位置,释放尾节点,将尾节点前一个节点的指针指向空。用两个指针,一个tail最后会指向尾节点,prev最后会指向尾节点前一个节点。
1.链表为空不删除
2.只有一个节点,此时删除后头指针需要指向空,因此是传址操作
3.有一个以上的节点
void SListPopBack(SListNode** pphead)
{
if (*pphead == NULL)
return;
else if ((*pphead)->next == NULL)//只有一个节点
{
free((*pphead)->next);
*pphead = NULL;
}
else
{
SListNode* prev = NULL;
SListNode* tail = *pphead;
while (tail->next)
{
prev = tail;
tail = tail->next;
}
free(tail);
prev->next = NULL;
}
4.链表的头插与头删
头插
创建新节点,将新节点的指针指向phead。
如果链表为空,指针指向phead,也就指向了NULL,此时链表有一个节点,但需要改变头指针,所以是传址操作。
如果链表有一个及以上的节点,操作与空链表时一样。
void SListPushFront(SListNode** pphead, SListDara x)
{
SListNode* newNode = CreatSListNode(x);
newNode->next = *pphead;
*pphead = newNode;
}
头删
同样头删也要改变头指针,所以传址操作。将头指针实现第二个节点,释放第一个节点。
如果链表为空不删除
void SListPopFront(SListNode** pphead)
{
if (*pphead == NULL)
return;
SListNode* first = *pphead;
*pphead = (*ppehad)->next;
free(first);
}
5.链表的查找与修改
查找
查找函数返回一个指针。指向要查找的节点,通过数据域查找节点,定义一个指针cur如果cur的data等于要查找的数据,函数返回,否则cur指向下一个节点。找不到返回NULL。
SListNode* SListNodeFind(SListNode* phead,SListData x)
{
if (phead == NULL)
return NULL;
SListNode* cur = phead;
while (cur)
{
if (cur->data == x)
return cur;
else
cur = cur->next;
}
return NULL;
}
修改
查找函数返回了节点的指针,对该指针解引用就能修改里面的数据。
SListNode* pos = SListNodeFind(pList, 2);
if (pos != NULL)
pos->data = 20;
//像这样操作
6.链表的节点插入与删除
插入
单链表的插入是将节点插入另一个节点之后。先创建一个新的节点,将该节点插入pos指针指向节点的后面,使pos指向的next指向新的节点,新节点的next指向pos之前指向的next。所以先将newNode的next指向pos的next,再将pos的next指向newNode。
viod SListInsertAfter(SListNode* pos, SListData x)
{
assert(pos);
SListNode* newNode = CreatSListNode(x);
newNode->next = pos->next;
pos->next = newNode;
}
删除
删除一个数删除的不是内存而是指向该内存的指针,也就是释放该指针。
删除的是pos后面的节点,先将该节点保存为next指针,需要使pos的指针指向nextnext。
如果pos是尾节点,后面没有节点则不要删除。如果pos后面只有一个节点,删除节点后pos的指针会指向空指针,pos成为尾节点。
void SListEraseAfter(SListNode* pos)
{
assert(pos);
if (pos->next)
{
SListNode* next = pos->next;
SListNode* nextnext = next->next;
free(next);
pos->next = nextnext;
}
}