在数据结构中我们经常会接触到链表,链表也分好多种,带头结点和不带头结点、循环和不循环、单向链表和双向链表
而在众多不同结构的链表中 带头循环双链表可以说是一种最优的链表结构
相比于单链表只能访问当前结点的后续结点的局限性,双链表既可以访问前面结点也可以访问后面结点
其次循环的情况下相比于非循环的链表在访问尾节点时,非循环的链表余姚遍历整个链表才能访问尾节点,而循环链表由于它的循环特性,不用遍历链表,头结点前一个结点就是尾节点,在访问速度上大大优于非循环链表
带头相对于不带头在对链表头插时候不会改变头结点的地址,不带头的每次头插和头删都会改变头指针,而带头结点可以解决这个问题
定义我们双链表结点的结构体,包括三个部分,_next和_prev指针分别指向下一个和前一个结点,_data用来存放数据
typedef
int
DataType
;
typedef
struct
DListNode
//结点
{
struct
DListNode
* _next;
struct
DListNode
* _prev;
DataType
_data;
}
DListNode
;
对于双链表的基础操作包括结点的插入,结点的删除,寻找某个结点,打印链表,销毁链表等
DListNode* BuyDListNode(
DataType
x
);
//创建新结点
DListNode
* DListInit();
//双链表初始化
void
DListDestory(
DListNode
*
head
);
//销毁链表
void
DListPrint(
DListNode
*
head
);
//打印链表
void
DListPushBack(
DListNode
*
head
,
DataType
x
);
//尾插
void
DListPushFront(
DListNode
*
head
,
DataType
x
);
//头插
void
DListPopBack(
DListNode
*
head
);
//尾删
void
DListPopFront(
DListNode
*
head
);
//头删
DListNode
* DListFind(
DListNode
*
head
,
DataType
x
);
//寻找值为x的结点,返回它的地址
void
DListInsert(
DListNode
*
pos
,
DataType
x
);
//在pos位置插入值为x的新结点
void
DListErase(
DListNode
*
pos
);
//删除pos位置结点
创建新的结点时用malloc申请空间,注意要判断是否申请成功,同时对_data赋值,对_prev 和_next指针置空,返回新开辟的结点地址
DListNode
* BuyDListNode(
DataType
x
)//创建新的结点
{
DListNode
* NewNode = (
DListNode
*)malloc(
sizeof
(
DListNode
));
if
(NewNode)
{
NewNode->_data =
x
;
NewNode->_next =
NULL
;
NewNode->_prev =
NULL
;
return
NewNode;
}
return
NULL
;
}
带头循环双链表初始化时是初始化链表的 头Head,同样用malloc申请空间,此时链表里面为空,但是由于是循环链表,所以这块对
Head->_next
和Head->_prev都指向头,也就是自己本身,返回Head的地址
DListNode
* DListInit()
//链表初始化
{
DListNode
* Head = (
DListNode
*)malloc(
sizeof
(
DListNode
));
if
(Head)
{
Head->_next = Head;
Head->_prev = Head;
return
Head;
}
return
NULL
;
}
插入操作
void
DListPushBack(
DListNode
*
head
,
DataType
x
)
//尾插
{
DListNode
* NewNode = BuyDListNode(
x
);
DListNode
* cur =
head
;
while
(cur->_next !=
head
)
{
cur = cur->_next;
}
cur->_next = NewNode;
NewNode->_prev = cur;
NewNode->_next =
head
;
head
->_prev = NewNode;
}
void
DListPushFront(
DListNode
*
head
,
DataType
x
)
//头插
{
DListNode
* NewNode = BuyDListNode(
x
);
DListNode
* cur =
head
->_next;
head
->_next = NewNode;
NewNode->_prev =
head
;
NewNode->_next = cur;
cur->_prev = NewNode;
}
void
DListInsert(
DListNode
*
pos
,
DataType
x
)
//在pos位置插入值为x的新的结点
{
DListNode
* tmp =
pos
->_prev;
DListNode
* NewNode = BuyDListNode(
x
);
tmp->_next = NewNode;
NewNode->_prev = tmp;
NewNode->_next =
pos
;
pos
->_prev = NewNode;
}
删除操作
void
DListPopBack(
DListNode
*
head
)
//尾删
{
DListNode
* cur =
head
->_prev->_prev;
free(
head
->_prev);
head
->_prev = cur;
cur->_next =
head
;
}
void
DListPopFront(
DListNode
*
head
)
//头删
{
DListNode
* cur =
head
->_next->_next;
free(
head
->_next);
head
->_next = cur;
cur->_prev =
head
;
}
void
DListErase(
DListNode
*
pos
)
//删除pos位置结点
{
DListNode
* tmp1 =
pos
->_prev;
DListNode
* tmp2 =
pos
->_next;
tmp1->_next = tmp2;
tmp2->_prev = tmp1;
free(pos);
pos = NULL;
}
寻找值为x的结点
DListNode
* DListFind(
DListNode
*
head
,
DataType
x
)
//寻找值为x的结点,返回它的地址
{
DListNode
* tmp =
head
->_next;
while
(tmp->_next !=
head
->_next)
{
if
(tmp->_data ==
x
)
{
return
tmp;
}
tmp = tmp->_next;
}
return
NULL
;
}
打印链表
void
DListPrint(
DListNode
*
head
)
//打印链表
{
assert
(
head
);
DListNode
* cur =
head
;
printf(
"Head->"
);
while
(cur->_next !=
head
)
{
cur = cur->_next;
printf(
"%d->"
, cur->_data);
}
printf(
"Head\n"
);
}
销毁链表
void
DListDestory(
DListNode
*
head
)
{
if
(
head
==
NULL
)
{
return
;
}
DListNode
* cur1 =
head
;
DListNode
* cur2 =
head
->_next;
while
(cur2)
{
free(cur1);
cur1 = cur2;
cur2 = cur2->_next;
}
}