一:定义链表
数据+指向下一个节点的指针
typedef int SLTDataType;
typedef struct SlistNode
{
int data;
struct SlistNode* next ;
}SLTNode;
上图即为一个简单的单链表。
下面初始化一个单链表:
1.1单链表的头插尾插
要做到头插/尾插,首先需要实现创建新节点
SLTNode* SLTBuyNode(SLTDataType x)
{
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
if (newnode == NULL)
{
perror("malloc fail!");
exit(1);
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
以上代码使用malloc函数,针对SLTNode的大小,给节点指针newnode分配空间,并将其存放的数据设置为x
1.1.1 头插实现
上传链表指向头节点(phead)的指针(pphead),使用BuyNode函数新建一个节点newnode,使其next指针指向原来的头节点phead
再将当前的newnode节点设置为头节点即可
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
assert(pphead);
SLTNode* newnode = SLTBuyNode(x);
newnode->next = *pphead;
*pphead = newnode;
}
1.1.2尾插实现
尾插的思路是遍历链表,找到链表最后一个节点
当某个节点的next指针指向空,即node->next==NULL,则代表该节点没有可指向的节点,即为尾节点
代码中的思路是从头节点开始,假设其就是尾节点,以“其next指针是否指向空”为循环条件遍历整个链表
如果链表为空,直接使用BuyNode函数新建一个节点newnode,将其设置为头节点即可。
void SLTPushBack(SLTNode** pphead,SLTDataType x)
{
SLTNode *newmode = SLTBuyNode(x);
if (*pphead == NULL)//空链表尾插
{
*pphead = newmode;
}
else//找到最后一个节点
{
SLTNode* ptail = * pphead;
while (ptail->next)
{
ptail = ptail->next;
}
//ptail 指向的就是最后一个节点
ptail->next = newmode;
}
}
2.1头删尾删
2.1.1头删
要想实现头删 有一些细节需要注意
我们需要先新建一个next节点用来存放phead的下一个节点,然后再删除phead,最后将刚才新建的next节点设置为phead
否则就会出现以下的情况:刚刚将phead设置为当前头节点的下一个节点,然后把phead删除了,那么这个头节点也就找不到了
void SLTPopHead(SLTNode** pphead)
{
assert(*pphead && pphead);
SLTNode* next = (*pphead)->next;//存放头节点的下一个节点 防止丢失
free(*pphead);
*pphead = next;
}
2.2.2尾删
与尾插思路相似,如果当前链表只有一个节点那么直接删除即可。
如果有多个节点则需要遍历链表找到倒数第二个节点
void SLTPopTail(SLTNode** pphead)
{
if ((*pphead)->next == NULL)
{
free(pphead);//只有一个节点
*pphead == NULL;
return;
}
SLTNode* cur = *pphead;
while (cur->next->next!=NULL)
{
cur = cur->next;
}
//此时cur为倒数第二个节点
free(cur->next);
cur->next == NULL;
}
while循环条件是:cur(当前节点)的next节点的next不指向空
如果满足此条件,则cur右移一个节点。
如果移动到倒数第二个节点,那么cur的下一个节点是尾节点,其next指向空,满足条件,将其free掉并置空即可。
3 打印
链表的打印实现起来,要依靠while循环遍历链表,打印出每个节点的数据即可
void SLTPrint(SLTNode* Phead)
{
SLTNode * pcur = Phead;
while (pcur)
{
printf("%d->", pcur->data);
pcur = pcur->next;
}
printf("Null\n");
}
4.销毁
void SLTDestroy(SLTNode** pphead)
{
assert(*pphead && pphead);
SLTNode* pcur = *pphead;
while (pcur)
{
SLTNode* next = pcur -> next;
free(pcur);
pcur = pcur->next;
}
*pphead = NULL;
}
这里要注意,新建一个pcur节点(当前节点)用来存放头节点指针,使用next节点存放pcur的下一个节点,然后遍历链表,先找到当前节点的下一个节点(next=pcur->next)再free掉当前节点,最后将当前节点后移一位。
整个循环结束后,最后删除头节点
以上是单链表的最基本的插入和删除等代码,下一篇会涉及到指定位置的插入和删除,以及一些相关oj题目