数据结构之链表的理解与相关代码演示

链表是数据结构中比较重要的内容,由于其代码中繁多的指针使用。使很多同学患上了链表恐惧症。正所谓会者不难,难者不会。多打代码多看代码就能让我们真正理解链表,并会使用链表。

这篇博客我们着重讨论无头单向不循环链表。

我们现在介绍一下链表的节点的结构体

typedef int SLDataType;

typedef struct SListNode{

SLDataTyope _data;//节点数据域

struct SListNode _next;//节点连接指针域

}SListNode;

可以把头结点封装起来,虽然在c语言中看来用处不大。外部依然可以修改访问它。但用c++来写的话,可以大大增加程序的安全性。

typedef struct SList{

SListNode=_head;

}SList;

首先来看链表的节点是如何构建出来的,构建节点的函数

思路非常简单:用一个新的指针申请相应的一个节点的空间,而后把相应的数组赋值给节点的数据域。

SListNode* CreatSListNode(SLDataType x){

SListNode *NewNode=(SListNode *)malloc(sizeof(SListNode));

NewNode->_data=x;

NewNode->_next=NULL;

return NewNode;

}

链表的初始化,可以说是最简单的了

void InitSList(SList *ps)

{

s->_head=NULL;

}

我们再来看看 链表的尾插代码

尾插思路:运用循环找到链表的尾部位置,而后把尾部与需要插入的节点连接起来。注意判断链表为空的情况

void SListPushBack(SList *ps,SLDataType x)

{

SListNode* cur=ps->_head;

if(ps->_head==NULL)

{

s->head=CreatSListNode(x);

}

else

{

while(cur->next);

{

cur=cur->_next;

}

cur->_next=CreatSListNode(x);

}

}

      在尾插代码中我犯过一个低级错误,导致代码老是出错,找了好多次都没找出来。在这里特别指出

尾插代码倒数第七行,当时我是这么写的

while(cur)

{

cur=cur->_next;

}

cur=CreatSlistNode(x);

}}

循环的逻辑没有什么问题,但是我把新建的节点赋值给了cur指针,并不管原链表的事情。意思就是这个新节点并没有连到相应的链表上。而是把新节点赋值给了cur指针,导致严重错误!!

接下来是头插代码

void SListHeadInsert(SList *ps,SLDataType x)

{

SListNode* cur=ps->_head;

SListNode *NewNode=CreatSListNode(x);

NewNode->=cur;

ps->head=NewNode;

}

头插没有什么好说的,记得把链表的头部重新赋值给新节点就好

接下来是头删和尾删接口,为什么把这两者放到一起来说呢!应为在链表的接口中。这两个接口一定要使用两个指针去记录被删节点的下一个节点/被删节点的前一个节点,这样才能保证把链表重新连接起来。

我们来说头删,代码如下

void SListPopFront(SList *ps)

{

/*SListNode *prev=ps->_head->_next;

SListNode *cur=ps->_head;

if(ps->_head==NULL)

{如果前部代码这么写的话,一旦链表头结点为空,prev就会出现问题。那么整个程序就会崩溃。所以要对位置进行斟酌

return;

}*/

if(p->_head==NULL)

{

return;

}

SListNode *prev=ps->_head->_next;

SListNode *cur=ps->_head;

free(cur);

cur=NULL;

ps->_head=prev;

return;

}

接下来来看尾删代码

尾删思路:找到最后一个节点,释放尾部的节点,将尾部的前一个一个节点的_next指向NULL,注意处理空链表和只有一个节点的情况

void SListPopBack(SList *ps)

{

if(ps->_head==NULL)

{

return;

}

SListNode *prev=NULL;

SListNode *cur=ps->_head;

while(cur->_next)

{

prev=cur;

cur=cur->_next;

}

if(prev==s->_head)

s->_head=NULL;

else{

free(cur);

prev->_next=NULL;

}

}

最主要的就是以上介绍的创建节点,头插,尾插,头删,尾删。。最主要的就是想清楚过程,代码实现的过程十分简单

来看看链表的打印函数

void PrintSList(SList*ps)

{

SListNode*cur=ps->_head;

if(cur==NULL)

return;

while(cur)

{

printf("%d->",cur->_data);

cur=cur->_next;

}

printf("\n");

}

链表的销毁接口代码。

void DestroySList(SList *ps)

{

SListNode *prev=NULL;

SListNode *cur=ps->_head;

while(cur)

{

prev=cur;

cur=cur->_next;

free(prev);

}

}

不用说,这个各位肯定看得懂

下来看链表的在pos位置处插入数据

思路:位置pos处已经给出,不用再从头结点向后一个个的找位置。

void SListInsert(SListNode *pos, SLDataType x)

{

SListNode* cur=pos->_next;

pos->_next=CreatSListNNode(x);

pos->_next->_next=cur;

}

在pos处后删除一个节点的函数

void PopSListNode(SListNode *pos)

{

SListNode *cur=pos->_next;

if(cur==NULL)

return;

stNode *prev=pos->_next->_next;

free(cur);

pos->_next=prev;

}

以上就是单链表所有的接口,在这里要注意几点

1.要修改指针的位置时,要传入二级指针的参数,这样才能够去改变指针的位置。这个道理就和传值调用与传址调用是一样的。

2.着重注意判断循环条件,看出循环时是尾指针还是尾指针的下一个指针。

3.当不能改表原链表节点时,要重新申请一个指针,对这个申请的指针进行操纵!!

再一个,要对链表的代码多写多练。这是做OJ题的基础!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值