对于单链表,首先是其定义需要用到数据和指向同种类型的指针,对于某个特定的单链表,要用地址来表示和寻找,找到该链表的地址,也就是找到了这个链表。
1:定义
typedef struct SListNode
{
int data;
struct SListNode* next;
}SLTNode,*Linklist;
指向同种类型的有next指针,通过typedef重命名为SLTNode,其中*Linklist是指向SLTNode类型的指针,其中*Linklist与SLTNode*是等价的。
2:创建新节点
SLTNode* BuyNewnode(int x)
{
SLTNode* tmp = new SLTNode;
tmp->data = x;
tmp->next = NULL;
return tmp;
}
在c++中,new返回的是创建的类型的地址,于是需要SLTNode*来接收,最后将该节点返回,于是返回类型便是SLTNode*,new出来的是地址,用到SLTNode*来接收创建类型的地址,通过该节点的地址可对其进行操作,最后返回的也是这个新节点的地址,只有拿到地址,才可对其进行操作。
3:头插
void SListPushFront(Linklist& l, int x)
{
SLTNode* tmp = BuyNewnode(x);
if (l == NULL)
l = tmp;
else
{
tmp->next = l;
l = tmp;
}
}
要操作的是这个链表本身,于是是&,但是操作某个特定的链表,需要拿到其地址才可操作,于是是Linklist类型,也就是SLTNode*类型。首先创建一个新节点,先进行一次判断,如果链表本来就为空,那么直接将新节点赋给l链表即可。如果不空,那么将新节点的next指向链表l,最后再将tmp赋给l,也就是l是Linklist型(SLTNode*类型),也是地址,一个链表用l来表示,那么l就要是这个链表的起始位置,也就是链表的开头,于是需要将tmp赋给l。
4:尾插
void SListPushBack(Linklist& l, int x)
{
SLTNode* tmp = BuyNewnode(x);
if (l == NULL)
l = tmp;
else
{
SLTNode* tail = l;
while (tail->next!=NULL)
{
tail = tail->next;
}
tail->next = tmp;
}
}
尾插和头插类似,刚开始都需要进行是否为空的判断,若空,则直接赋值即可。如果不空,首先需要一个指针,命名为tail,因为是尾插,一定要寻找最后一个节点。首先令tail指向l(也就是链表的开头),下面使用while循环,注意这里是tail->next!=NULL,当tail->next为空时,也就是最后一个节点,即尾结点。找到后,将tail指向的尾结点的next指向新节点tmp即可(在调用创建新节点函数时,新节点的next便已经被赋值为NULL了,于是这里不需要对新节点的next再操作)
5:头删
void SListPopFront(Linklist& l)
{
if (l == NULL)
return;
else if (l->next == NULL)
delete l;
else
{
SLTNode* tmp = l->next;
delete l;
l = tmp;
}
}
这里将头删分为了3种情况。第一种如果链表是空,一个节点都没有,那么直接return 退出这个函数。第二种如果只有一个节点,那么直接删去即可。第三种是有多个节点,那么先定义一个指针指向l的下一个节点,删去l这个头结点,再令l 指向新的头结点。
6:尾删
void SListPopBack(Linklist& l)
{
if (l == NULL)
return;
else if (l->next == NULL)
{
delete l;
}
else
{
SLTNode* tail = l;
SLTNode* prev = NULL;
while (tail->next!=NULL)
{
prev = tail;
tail = tail->next;
}
prev->next = NULL;
delete tail;
}
}
尾删是三种情况。第一种是链表为空的话,直接return退出该函数。第二种是只有一个节点,那么直接删除即可。第三种是有多个节点,因为是尾删,那么需要找到尾结点,因为需要在尾结点的前一个节点的next赋值为NULL,所以还需要找到尾结点的前一个节点。在此定义tail指针,指向l来寻找尾结点,另一个prev指针先指向空,来寻找尾结点的前一个节点。于是while训话中用tail来找到尾结点,prev在到达tail的位置后,tail 再指向tail 的next,找到后,将prev的next赋值NULL,删除tail指向的尾结点即可。
7:查找
SLTNode* SListFind(Linklist l, int x)
{
SLTNode* p = l;
while (p != NULL)
{
if (p->data == x)
return p;
p = p->next;
}
return NULL;
}
这里的查找是返回这个节点,包括它的数据和next,因为找到某个具体的节点或者需要对节点操作,那么必须要得到它的地址才行,于是返回的类型便是SLTNode*类型,再通过data数值进行查找,找到后返回即可。
8:插入
void SListInsert(Linklist& l, SLTNode* pos,int x)
{
SLTNode* tmp = BuyNewnode(x);
if (l== pos)
{
SListPushFront(l, x);
}
else
{
SLTNode* prev = l;
while (prev->next != pos)
{
prev = prev->next;
}
tmp->next = prev->next;
prev->next = tmp;
}
}
插入首先需要创建一个新节点,可调用函数实现。分为2种情况,如果需要在头结点之前插入,那么便是头插,可调用函数实现。第二种便是在其他位置插入,首先便要找到pos节点的前驱,此时通过prev指针,通过循环它的next来找到pos 的前驱节点,找到后将prev指向的节点的next 值指向新节点的next值,也就是新节点的next就是pos节点。再将新节点赋给prev的next即可成功链接。
9:删除
void SListErase(Linklist& l, SLTNode* pos)
{
if (pos == l)
{
SListPopFront(l);
}
else
{
SLTNode* prev = l;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
delete pos;
}
}
两种情况。如果删除的位置是头结点,那么便是头删,可调用函数实现。其他节点仍是通过prev找到要删除的pos指向的节点的前驱,然后prev 的next指向pos 的next,最后删除pos即可。
10:打印
void print(Linklist l)
{
SLTNode* p = l;
while (p != NULL)
{
cout << p->data << " ";
p = p->next;
}
cout << "\n";
}
打印函数无需多说,当p不为NULL时打印再向后移动即可。
最后是使用test函数来测试所有代码
void test()
{
Linklist l = NULL;
SListPushBack(l, 1);
SListPushBack(l, 2);
SListPushBack(l, 3);
SListPushBack(l, 4);
SListPushFront(l, 5);
SListPushFront(l, 6);
print(l);
SListPopFront(l);
print(l);
SListPopBack(l);
print(l);
SLTNode* pos = SListFind(l, 3);
SListInsert(l, pos, 33);
print(l);
pos = SListFind(l, 5);
SListInsert(l, pos, 10);
print(l);
pos = SListFind(l, 10);
SListErase(l, pos);
pos = SListFind(l, 33);
print(l);
SListErase(l, pos);
print(l);
}
最终的全代码在下方:
#include<iostream>
using namespace std;
typedef struct SListNode
{
int data;
struct SListNode* next;
}SLTNode,*Linklist;
void print(Linklist l)
{
SLTNode* p = l;
while (p != NULL)
{
cout << p->data << " ";
p = p->next;
}
cout << "\n";
}
SLTNode* BuyNewnode(int x)
{
SLTNode* tmp = new SLTNode;
tmp->data = x;
tmp->next = NULL;
return tmp;
}
void SListPushFront(Linklist& l, int x)
{
SLTNode* tmp = BuyNewnode(x);
if (l == NULL)
l = tmp;
else
{
tmp->next = l;
l = tmp;
}
}
void SListPushBack(Linklist& l, int x)
{
SLTNode* tmp = BuyNewnode(x);
if (l == NULL)
l = tmp;
else
{
SLTNode* tail = l;
while (tail->next!=NULL)
{
tail = tail->next;
}
tail->next = tmp;
}
}
void SListPopBack(Linklist& l)
{
if (l == NULL)
return;
else if (l->next == NULL)
{
delete l;
}
else
{
SLTNode* tail = l;
SLTNode* prev = NULL;
while (tail->next!=NULL)
{
prev = tail;
tail = tail->next;
}
prev->next = NULL;
delete tail;
}
}
void SListPopFront(Linklist& l)
{
if (l == NULL)
return;
else if (l->next == NULL)
delete l;
else
{
SLTNode* tmp = l->next;
delete l;
l = tmp;
}
}
SLTNode* SListFind(Linklist l, int x)
{
SLTNode* p = l;
while (p != NULL)
{
if (p->data == x)
return p;
p = p->next;
}
return NULL;
}
void SListInsert(Linklist& l, SLTNode* pos,int x)
{
SLTNode* tmp = BuyNewnode(x);
if (l== pos)
{
SListPushFront(l, x);
}
else
{
SLTNode* prev = l;
while (prev->next != pos)
{
prev = prev->next;
}
tmp->next = prev->next;
prev->next = tmp;
}
}
void SListErase(Linklist& l, SLTNode* pos)
{
if (pos == l)
{
SListPopFront(l);
}
else
{
SLTNode* prev = l;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
delete pos;
}
}
void test()
{
Linklist l = NULL;
SListPushBack(l, 1);
SListPushBack(l, 2);
SListPushBack(l, 3);
SListPushBack(l, 4);
SListPushFront(l, 5);
SListPushFront(l, 6);
print(l);
SListPopFront(l);
print(l);
SListPopBack(l);
print(l);
SLTNode* pos = SListFind(l, 3);
SListInsert(l, pos, 33);
print(l);
pos = SListFind(l, 5);
SListInsert(l, pos, 10);
print(l);
pos = SListFind(l, 10);
SListErase(l, pos);
pos = SListFind(l, 33);
print(l);
SListErase(l, pos);
print(l);
}
int main()
{
test();
return 0;
}
输出结果:
![](https://i-blog.csdnimg.cn/blog_migrate/c553029ee7abd0085f4cb5a870e9cb46.png)