在正式讲解链表的拓展问题时,我再谈谈我对链表框架的看法。
链表的组成成员是结点,但是只有结点是不行的,还需要有链表的框架。这就需要一个函数来初始化链表,想要敲出一个函数并不是太难,但是想要你的函数在整个程序中正常运行往往还缺很多,主要原因还是缺乏对于框架性知识的理解,所以在写链表的时候,首先是定义结点,然后要购买结点,然后初始化链表,最后将结点插入完成链表。
- 单项循环链表
单项循环链表和单链表相差不大,只不过是将尾指针的后继指向了头,区别在于链表初始化的时候修改last指针的指向,last的后继指针不再指向NULL,而是指向头结点的位置,注意就是在创建时用的头插法和尾插法最后需要修改last指针的指向。在显示函数的时候不再是遇到空访问停止,而是遇到头结点访问停止。
来看一下主要创建链表的核心代码
void ListInit(SLIST* psl)
{
Listnode* S = _Buynode(0);
psl->first = psl->last = S;
psl->last->next = psl->first;
psl->size = 0;
}
bool ListPushback(SLIST* psl,int y)
{
Listnode* s = _Buynode(y);
if (s == NULL)
return false;
psl->last->next = s;
psl->last = s;
psl->size++;
psl->last->next = psl->first;
return true;
}
bool ListPushFront(SLIST* psl, int y)
{
Listnode* s = _Buynode(y);
if (s == NULL)
return false;
if (psl->size == 0)
{
psl->last->next = s;
psl->last = s;
}
else
{
s->next = psl->first->next;
psl->first->next = s;
}
psl->size++;
psl->last->next = psl->first;
return true;
}
显示函数
void ListShow(SLIST* psl)
{
Listnode* p;
p = psl->first->next;
while (p != psl->first)
{
printf("%d ", p->data);
p = p->next;
}
}
- 双向链表:
双向链表和单链表差别也不大,双链表相比较单链表而言在指针域多了指向前驱结点的指针,这就造成了双链表进行增删查改等的基础操作上有了很大的该变,同时又方便了很多。因为双向链表的时候有了前驱指针这条链,就不容易造成链表的断链。来看下面代码。
首先是创建节点,这个节点会多一个prew指针来记录结点的前驱。
typedef struct DListnode
{
int data;
struct DListnode* next;
struct DListnode* prew;
}DListnode;//创建一个节点
接下来就是这个链表的怎么来创建
还是和单链表一样有一个记录头的指针和一个记录尾的指针,还有一个记录链表长度的无符号整型变量。
在初始化化链表的时候首先指向链表的2个指针指向头,而且头的地址为空。
基本上创建完成后就是完成这个双链表的各项功能,基本上掌握了单链表其他链表基本上就能掌握了,因为这里面的区别不大。
当然我们需要一种更高级的形式展现链表,不能像之前那样用啥将函数写出来调用,我们需要做个菜单。来看代码
while (1)
{
printf("*****************************************************\n");
printf("*****[1]PushBank [2]PushFront***************\n");
printf("*****[3]PopBank [4]PopFront****************\n");
printf("*****[5]ListShow [6]FindBuyVal**************\n");
printf("*****[7]DeleteBuyVal [8]ReplaceByVal************\n");
printf("*****[9]DListReverse [10]DListBreak*************\n");
printf("*****************************************************\n");
printf("*****************************************************\n");
printf("请选择->");
scanf("%d", &select);
if (select == 0)
break;
switch (select)
在菜单中完成想要的操作
- 双向循环链表
接下来我们来看双向循环链表。在生活中我们遇到最多的就是单链表和双向循环链表。我们来看一下双向循环链表的基本操作应该怎么完成。仿照单链表变成单循环链表,我们不难发现,双向链表变成双向循环链表实质上就是更改了尾指针。尾指针不在指向空,尾指针指向了头。在操作中的差异和双链表的区别不大。
a. 首先是链表初始化
bool DListNodeInit(SLIST* psl)
{
DListnode* s = _BuyDNode(0);
if (s == NULL)
return false;
psl->last = psl->first = s;
psl->last->next = psl->first;
psl->first->prew = psl->last;
psl->size = 0;
return true;
}
b. 链表的头尾插
bool DListPushback(SLIST *psl, int x)
{
DListnode* S = _BuyDNode(x);
if (S == NULL)
{
return false;
}
psl->last->next = S;
S->prew = psl->last;
psl->last = S;
psl->last->next = psl->first;
psl->first->prew = psl->last;
psl->size++;
return true;
}
bool DListPushFront(SLIST* psl, int x)
{
DListnode* P = _BuyDNode(x);
if (P == NULL)
return false;
if (psl->size == 0)
{
psl->last->next = P;
P->prew = psl->first;
psl->last = P;
psl->last->next = psl->first;
psl->first->prew = psl->last;
psl->size++;
}
else
{
P->next = psl->first->next;
psl->first->next = P;
psl->size++;
}
return true;
}
c. 链表的显示
void ShowDlist(SLIST* psl)
{
if (psl->size > 0)
{
DListnode* P = psl->first->next;
while (P != psl->first)
{
printf("%d", P->data);
printf("->");
P = P->next;
}
}
}
剩下操作和单链表差异不大,总之想掌握好链表还是需要下和很多功夫,链表的实际操作来说并不算难,但是却很容易出错,希望大家和我一起在不断练习当中慢慢掌握好它,整整做到学以致用。