我们来看单链表的销毁,排序,逆置
首先还是来看一下单链表的销毁
我们能不能将单链表的操作像顺序表一样直接将他的size变成0然后直接释放掉指向他的空间?
void listDestory(SLIST *psl)
{
psl->size = 0;
free(psl);
}
我们知道链表存储数据最大的不同就是不是一段连续的空间,如果释放链表空间,需要释放每一个节点的空间,而不是直接将头节点的空间释放就可以。这个函数操作就是将链表断开然后直接对头结点进行free;但是剩下的节点不仅没有释放掉空间还找不到了,因此我们对于链表空间的释放还需要进行深究
在销毁链表之前我们先做出链表清除的函数
注意,在释放空间的时候,稍有不慎就有可能断链,导致后面所有的找不到。
void listClearList(SLIST* psl)
{
Listnode* P;
P = psl->first->next;
while (P->next != NULL)
{
psl->first->next = P->next;
free(P);
P = psl->first->next;
}
psl->first = psl->last;
psl->size = 0;
}
这样就能实现链表的清除,节点依次释放;
接下来看链表的销毁操作
只需要在清除操作上加一点,将头节点释放掉就行。
void listDestory(SLIST *psl)
{
listClearList(psl);
free(psl->first);
psl->first = psl->last = NULL;//为了规避野指针
}
接下来我们来看链表的逆置问题,注意,链表逆置并非将链表倒着打印出来 ,而是将节点逆置。实质上是修改节点的指针
常见的方法有2指针方法和3指针方法
方法一:将一个链表看成2个链表,第一个链表只有一个头结点个一个节点,剩余的构成第二个节点,每次从第二个链表中取出1个节点在第一个链表上进行头插。这就将不会的转换成会的。
首先我们来看三指针逆置
void ReserveList(SLIST* psl)
{
Listnode*p;
Listnode*q;
Listnode*temp;
p = psl->first->next;
q = p->next;
temp = q->next;
p->next = NULL;//将链表断成2个链表
//while (temp != NULL)
while(q != NULL)
{
q->next = p;
psl->first->next = q;
q = temp;
if(temp != NULL)//一定要加这条判断语句,不然会导致末尾插不进去
temp = temp->next;
p = psl->first->next;//p 第二个
}
}
我们来分析一下这段代码,首先3个指针的位置一定要确定好,p指针一直指向psl->first->next,temp 指针用来记录q指针的位置,q指针是断链后的后面你的链表,一直指向第二个链表的头位置,然后将其做头插插入到前面的链表中。
还有一种方法是二指针法,其实三指针的操作双指针万全可以完成但是链表操作不好很容易断链。我们来看下双指针解决逆置问题
其实说的双指针,但是真正见到代码是加上还是3指针,但是这个额外的指针是用的是这个链表本身就带有的指针 last ,只不过我们再三指针的时候并没有用到这个指针。
来看双指针时刻的代码
void ReserveList1(SLIST* psl)
{
Listnode *p;
Listnode *q;
p = psl->first->next;
q = p->next;
p->next = NULL;
psl->last = p;
p = q;
while ( q !=NULL)
{
q = q->next;
p->next = psl->first->next;
psl->first->next = p;
p = q;
}
}
我们继续看操作,链表的排序问题,这里面的排序指的并不是更改链表的数据域,而是更改其指针与让整个链表按照规定顺序排列。
链表排序问题进行之前我们先来回顾一下链表的按值插入问题
首先就是这个指针如何找到这个插入点的位置,我们可以用while循环来操作,找到后看情况是否在链表末尾处。
void InsertByVal(SLIST* psl,int x)
{
Listnode* p;
p = psl->first;
while (p->next != NULL && x > p->next->data)
{
p = p->next;
}
Listnode* L = _Buynode(x);
if (p->next == NULL)
{
p->next = L;
psl->last = L;
}
else
{
L->next = p->next;
p->next = L;
}
psl->size++;
}
有了按值插入我们来看下排序问题,实际上可以将链表断成个链表,然后将第二个链表的值做按值插入操作。
void slistSort(SLIST* psl)//还是将链表断开然后按值插入
{
if (psl->size > 1)
{
Listnode *prev;
Listnode *p = psl->first->next;
Listnode *q = p->next;
psl->last = p;
psl->last->next = NULL;
p = q;
while (p != NULL)
{
q = q->next;
prev = psl->first;
while (prev->next != NULL && p->data > prev->next->data)
prev = prev->next;
if (prev->next == NULL)
{
prev->next = p;
psl->last = p;
p->next = NULL;
}
else
{
p->next = prev->next;
prev->next = p;
}
p = q;
}
}
}