不带头结点的单链表如图所示:
1、初始化链表//将头指针置空,对头指针进行操作,所以参数为引用
void InitList(LinkList &slink)
{
slink = NULL;
}
2、销毁链表//将malloc的空间全free掉,将头指针置空,所以参数是引用
void Destroy(LinkList &slink)
{
/*
遍历表,逐个free当前链表,直至表尾
1、需要变量指向当前变量p
2、需要变量保存当前变量的next
2、循环条件当前变量是否为空
*/
LinkList p= slink,q;
while(p)
{
q= p->next;
free(p);
p = q;
}
slink = NULL;
}
以上过程还可以简化如下:
用链表的头指针始终指向当前结点,这样就可以少定义一个变量(这区别于带头结点的链表)
void Destroy(LinkList &slink)
{
/*
遍历表,逐个free当前链表,直至表尾
1、需要变量指向当前变量
2、需要变量保存当前变量的next
2、循环条件当前变量是否为空
*/
LinkList q;
while(slink)
{
q= slink->next;
free(slink);
slink = q;
}
//slink = NULL;
}
小结:while循环条件中变量的值,跳出循环后,最终是等于不满足循环条件的那个值。
或者用变量q先保存住头指针,然后,头指针指向他的next,最后,释放掉q
void destroyList(LinkList &slink)
{
/*
遍历表,逐个free当前链表,直至表尾
1、需要变量指向当前变量
2、需要变量保存当前变量的next
2、循环条件当前变量是否为空
*/
LinkList q;
while(slink)
{
q= slink;
slink = slink->next;
free(q);
}
//slink = NULL;
}
3、将链表数据清空
//与销毁表完全相同
#define clearList destroyList
给destroyList 起个新名字叫clearList
4、求链表的长度
int LengthList(LinkList L)
{
int i=0; //计数变量
LinkList p =L; //指向当前结点的变量
while(p)
{
i++;
p = p->next;
}
return i;
}
5、链表中插入元素
寻找i-1的位置,可以包含住在链尾插入元素的情况。
插入元素前,一定要先保存好i-1的next指针,因为,这个会被改变,而改变了的话,就无法找到i结点了。
不带头结点的链表,插入结点操作时,需要传引用,因为如果在表头插入的话,会改变链表。
方法一:
bool insertList(LinkList &slink,int e,int i)
{
/*
思路:寻找i-1的位置,因为找到i-1就能找到i及i+1的位置
i的范围是1-最后一个结点+1
1、计数变量j
2、当前结点变量
3、临时变量用来malloc
4、循环条件,
*/
if(i<1) return false;
int j=1;
LinkList p = slink;
LinkList q = (LinkList)malloc(sizeof(Node));
q->data = e;
if(i==1)
{
q->next = p;
slink = q;//此处得用slink,因为链表改变了。
return true;
}
while(p&&j<i-1)//j=1,代入,i>2,未包含i=1的情况
{
p = p->next;
j++;
}
if(p)
{
q->next = p->next;
p->next = q;
return true;
}
return false;
}
方法二:
bool insertList(LinkList &slink,int e,int i)
{
/*
思路:寻找i-1的位置,因为找到i-1就能找到i及i+1的位置
i的范围是1-最后一个结点+1
1、计数变量j
2、当前结点变量
3、临时变量用来malloc
4、循环条件,
*/
if(i<1) return false;
int j=1;
LinkList p = slink;
LinkList q = (LinkList)malloc(sizeof(Node));
q->data = e;
if(i==1)
{
q->next = slink;
slink = q;//此处得用slink,因为链表改变了。
return true;
}
while(p&&j<i-1)//j=1,代入,i>2,未包含i=1的情况
{
p = p->next;
j++;
}
if(!p)
return false;
q->next = p->next;
p->next = q;
return true;
}
注意:程序中,只用了if(!p).....,是因为前面已经判断了i<1的情况了。
6、链表中删除数据
bool deleteList(LinkList &slink,int i)
{
/*
缩小i的范围:i的值从1-表尾
找第i-1个结点
1、变量计数
2、变量指向当前结点
3、循环条件:当前结点不为空,计数小于i-1
*/
int j=1;
LinkList p = slink;
LinkList temp ;
if(i==1)
{
slink = slink->next;
free(p);
return true;
}
while(p&&j<i-1);//代入j=1,i>2,故未包含i=1的情况
{
P = P->next;
j++;
}
if(!p||j>i-1)
return false;
temp = p->next;
p->next = temp->next;
free(temp);
return true;
}
注意:与删除结点的方法二进行比较会发现,此处多了j>i-1,少了if(i<0) return false;的情况,
代数检查可以验证,加上j>i-1条件,可以排除掉i<0的情况。
7、链表中返回元素的直接前驱
注意:找前驱的话,循环条件要判断当前值的后继是否为空,如果判断当前值的话,就无法找到前驱了。
方法一:正向思维
void priorList(LinkList slink,int value,int &e)
{
/*
该值的范围:
从第一个结点的后继开始,判断到倒数第二个结点的后继
1、变量指向当前结点
*/
LinkList p = slink;
LinkList q;
while(p->next)
{
q = p->next;
if(q->data==value)
{
e = p->data;
return true;
}
p = q;
}
return false;
}
方法二:逆向思维
void priorList(LinkList slink,int value,int &e)
{
/*
该值的范围:
从第一个结点的后继开始,判断到倒数第二个结点的后继
1、变量指向当前结点
*/
LinkList p = slink;
LinkList q;
while(p->next&&p->next->data!=value)
{
p = p->next;
}
if(p->next)
{
e = p->next->data;
return true;
}
return false;
}
8、返回与链表中某值相等元素的直接后继
方法一:正向思维
void nextList(LinkList slink,int value,int &e)
{
/*
1、指向当前结点的变量
3、循环条件:当前结点的后继结点不为空
此次,我们次用正向思维方式,while循环中找到该值返回
*/
LinkList p = slink;
while(p->next)
{
if(p->data == value)
{
e = p->next->data;
return true;
}
p = p->next;
}
return false;
}
方法二: 逆向思维
void nextList(LinkList slink,int value,int &e)
{
LinkList p = slink;
while(!p->next&&p->data != value)
{
p = p->next;
}
if(!p->next)
{
e = p->next->data;
return true;
}
return false;
}