目录:
1、初始化
2、头部插入
3、头部删除
4、尾部插入
5、尾部删除
6、打印链表
7、任意位置插入
8、查找值为data的节点
9、指定位置删除
10、销毁链表
###1、初始化:
创建一个节点,给节点赋值为0;因为是循环链表,所以让它的_pNext指针域和_pPre 指针域都指向自己
void DCListInit (DCList** p)//初始化
{
DCList *cur = NULL;
assert (p != NULL);
cur = (DCList*)malloc (sizeof (DCList));
if (NULL == cur)
{
printf ("初始化操作失败\n");
exit (EXIT_FAILURE);
}
*p = cur;
(*p)->data = 0;
(*p)->_pNext = *p;
(*p)->_pPre = *p;
}
运行结果如图:
###创建一个新节点
在操作过程中,像插入等操作,还需要创建新节点,将其写成一个函数,代码如下:
DCList* DCBuyNode(DCDataType data)
{
DCList* cur = (DCList*)malloc(sizeof (DCList));
if (cur == NULL)
{
perror ("DCBuyNode::malloc >>");
return NULL;
}
cur->data = data;
cur->_pNext = NULL;
cur->_pPre = NULL;
return cur;
}
###2、头部插入
先找到最后一个节点,用tail标记,在让新节点接在链表第一个节点的前面,然后再将新节点和头结点相连,最后让新节点作为链表的头,如下图:
void PushFrontDCList (DCList** p, DCDataType data)//头插
{
DCList* NewNode = NULL;
DCList* tail = NULL; //标记最后一个节点
assert (p != NULL);
NewNode = DCBuyNode (data);
tail = (*p);
while (tail->_pNext != *p)
{
tail = tail->_pNext;
}
NewNode->_pNext = (*p);
(*p) ->_pPre = NewNode;
tail ->_pNext = NewNode;
NewNode->_pPre = tail;
*p = NewNode;
}
通过调用打印链表的函数,执行结果如下:
###3、头部删除
头部删除时删除的是第一个节点,要分情况讨论,当链表只有一个节点时:只需要删除这一个节点;当有多个节点时,分两步,先把第一个节点从链表上拆下来,在删除第一个节点,让现在链表中的第一个节点作为新链表的第一个节点;
void PopFrontDCList (DCList**p)//头删
{
DCList *del = NULL;
DCList *tail = NULL;
DCList *cur = NULL;
assert (p != NULL);
del = *p;
//当链表只有一个节点时
if ((*p)->_pNext == *p)
{
free (del);
del = NULL;
*p = NULL;
printf ("链表为空!!!\n");
return ;
}
//链表有两个及以上的节点时
tail = (*p)->_pNext;
cur = (*p)->_pNext;
while (tail->_pNext != *p) //找最后一个节点
{
tail = tail->_pNext;
}
tail ->_pNext = cur;
cur->_pPre = tail; //把第一个节点从链表上拆下来
free (*p); //删除第一个节点
(*p) = NULL;
(*p) = cur;
}
通过调用打印函数,执行结果如下:
###4、链表的打印
这里的链表打印有两种,主要是因为在初始化时让第一个节点的值为零,所以实际上链表中的值还多出来一个0,当使用头插时,0在链表中最后一个节点,当使用尾插时,0在链表中最前面的节点,具体代码如下:
void PrintDCList_F (DCList* p) //打印链表(头插的打印方式)
{
DCList* cur = p;
assert (p != NULL);
if (p->_pNext == p)
{
printf ("链表为空!!!\n");
return;
}
while (cur->_pNext != p)
{
printf ("%d ", cur->data);
cur = cur->_pNext;
}
printf ("\n");
}
void PrintDCList_B (DCList* p) //打印链表(尾插的打印方式)
{
DCList* cur = p->_pNext;
assert (p != NULL);
if (p->_pNext == p)
{
printf ("链表为空!!!\n");
return;
}
while (cur != p)
{
printf ("%d ", cur->data);
cur = cur->_pNext;
}
printf ("\n");
}
5、尾部插入
尾部插入也分为两步:先找最后的一个节点,在将新节点和最后一个节点和第一个节点连起来,这里找最后一个节点也可以通过第一个节点的前驱节点来找。
void PushBackDCList (DCList** p, DCDataType data) //尾部插入
{
DCList* cur = NULL;
DCList* tail = NULL;
assert (p != NULL);
cur = DCBuyNode(data); //新节点
tail = *p;
while (tail->_pNext != *p) //找最后一个节点
{
tail = tail->_pNext;
}
tail->_pNext = cur;
cur->_pPre = tail;
cur->_pNext = (*p);
(*p)->_pPre = cur;
}
运行结果:
6、尾部删除
这里的删除方法也与之前的类似,就是找到要删除的点,将它从链表上拆下来并把它删除,所以后面的就不再细说了;
void PopBackDCList (DCList** p) //尾删
{
DCList* del = NULL;
DCList* pre = NULL;
assert(p != NULL);
del = *p;
if ((*p)->_pNext == (*p)) //如果只有一个节点
{
free (del);
del = NULL;
*p = NULL;
printf ("链表为空!!\n");
return ;
}
//如果有多个节点
del = *p;
while (del->_pNext != *p)
{
pre = del;
del = del->_pNext;
}
pre->_pNext = *p;
(*p)->_pPre = pre;
free (del);
del = NULL;
}
###7、查找节点
查找节点就是简单的遍历链表,一次比较是否是要查找的节点
DCList* FindDCNode (DCList* p, DCDataType data) //查找值为data的节点
{
DCList* cur = p->_pNext;
while (p != cur)
{
if (cur->data == data)
{
return cur;
}
cur = cur->_pNext;
}
return NULL;
}
###8、任意位置插入
void InsertDCList (DCList** p, DCList* pos, DCDataType data) //任意位置插入
{
DCList* new_node = NULL;
assert (p != NULL && pos != NULL);
new_node = DCBuyNode(data);
pos->_pPre->_pNext = new_node;
new_node->_pPre = pos->_pPre;
new_node->_pNext = pos;
pos->_pPre = new_node;
}
###9、任意位置删除
void DeleteDCNode (DCList** p, DCList* pos) //任意位置删除元素
{
DCList* del = NULL;
assert (p != NULL);
pos->_pNext->_pPre = pos->_pPre;
pos->_pPre->_pNext = pos->_pNext;
free (pos);
pos = NULL;
}
10、销毁链表
遍历链表,一次销毁所有节点
void DestroyDCList (DCList** p) //销毁链表
{
DCList* pre = NULL;
DCList* tail = NULL; //用来标记最后一个节点
assert (p != NULL);
tail = (*p)->_pPre;
while (*p != tail)
{
pre = (*p);
(*p) = (*p)->_pNext;
free (pre);
pre = NULL;
}
free (*p);
(*p) = NULL;
}