双链表
一:双链表简介
带头非循环双链表示意图
- 1.每个结点都有两个指针域(一个指向其前面的结点,一个指针指向其后一个结点).
- 2.链表的头结点的prev指针和尾结点的next指针都指向NULL
- 3.物理上非连续,逻辑上连续
二:双链表的具体实现
2.1:双链表结构的定义
typedef int DLDataType;
typedef struct DListNode{
DLDataType _value;
struct DListNode* _prev;
struct DListNode* _next;
}DListNode;
2.2:定义指向双链表头结点的头指针
typedef struct DList{
DListNode* head;
} DList;
2.3:双链表的初始化
void DListInit(DList *dlist){
assert(dlist!=NULL);
dlist->head=DListBuyNode(0);
dlist->head->_prev=NULL;
dlist->head->_next=NULL;
}
2.4:定义一个专门用来申请新结点的函数
DListNode * DListBuyNode(DLDataType value){
DListNode* new_node=(DListNode*)malloc(sizeof(DListNode));
new_node->_value=value;
new_node->_prev=NULL;
new_node->_next=NULL;
return new_node;
}
2.5:清空双链表(保留了头结点)
- 1.定义一个指针cur用于遍历整个双链表的每一个结点
- 2.定义一个指针tmp指向指针 cur 所指的那个结点
- 3.指针cur再指向其所结点的下一个结点位置
- 4.释放tmp所指的空间 ,只到cur下一个结点为空
void DListClear(DList *dlist){
assert(dlist!=NULL);
assert(dlist->head!=NULL);
DListNode* cur=dlist->head->_next;
while(cur->_next!=NULL){
DListNode* tmp=cur;
cur=cur->_next;
free(tmp);
}
dlist->head->_next=dlist->head->_prev=NULL;
}
2.6:清空双链表(将头结点也释放)
- 1.调用双链表结点的清除函数
- 2.将头结点也释放了,并将头指针置为NULL
void DListDestory(DList *dlist){
assert(dlist!=NULL);
DListClear(dlist);
free(dlist->head);
dlist->head=NULL;
}
2.7:双链表的头插
- 1.定义一个指向双链表头结点的指针cur(用于遍历整个双链表)
- 2.申请一个新的结点并将值赋为所给的值
- 3.让新结点的next 指针指向cur的下一个结点
- 4.让cur的next指针指向的结点的prev指针指向新结点
- 5.让新结点的prev指针指向头结点,让cur的next指向新结点
void DListPushFront(DList *dlist,DLDataType value){
assert(dlist!=NULL);
assert(dlist->head!=NULL);
DListNode* cur=dlist->head;
DListNode* new_node=DListBuyNode(value);
new_node->_next=cur->_next;
if(cur->_next!=NULL)
cur->_next->_prev=new_node;
new_node->_prev=cur;
dlist->head->_next=new_node;
}
2.8双链表的尾插
- 1.定义指向结点类型的指针cur 指向头结点的下一个结点(用于遍历整个双链表)
- 2.让cur遍历双链表的结点知道遇见最后一个结点
- 3.让cur 的next指针指向新结点
- 4.让新结点的prev指针指向原来的尾结点,再让新结点的next指针指向NULL
void DListPushBack(DList *dlist, DLDataType value){
assert(dlist!=NULL);
DListNode* node=DListBuyNode(value);
DListNode* cur=dlist->head;
while(cur->_next!=NULL){
cur=cur->_next;
}
cur->_next=node;
node->_prev=cur;
node->_next=NULL;
}
2.9:双链表中查找结点值与指定值相等的结点
- 1.定义指向头结点下一个结点的指针cur(用于遍历真个双链表)
- 2.开始查找结点值与指定值相等的结点,此过程中cur不断的指向它的下一个结点位置
- 3.找到返回该结点的位置,否则返回NULL
DListNode * DListFind(DList *dlist,DLDataType value){
assert(dlist!=NULL);
DListNode* cur=dlist->head->_next;
while(cur!=NULL){
if(cur->_value==value)
return cur;
cur=cur->_next;
}
return NULL;
}
2.10:在指定双链表的指定位置插入新的结点
- 1.申请一个新的结点,将结点的值设为指定的值
- 2.让新结点的next指针指向pos位置的结点
- 3.让pos位置结点的prev所指结点的next指针指向新的结点
- 4.让新结点的prev指针指向pos位置结点的prev指针指向的结点
- 5.让pos位置结点的prev指针指向新结点
void DListInsert(DListNode *pos, DLDataType value){
DListNode* node=DListBuyNode(value);
node->_next=pos;
node->_prev=pos->_prev;
pos->_prev->_next=node;
pos->_prev=node;
}
2.11:删除指定位置的结点
- 1.让pos位置结点的prev指针指向结点的next指针指向pos位置结点的next结点
- 2.让pos位置结点的next指针指向结点的prev指向pos位置结点的前一个结点
- 3.释放pos所在位置的结点空间
void DListErase(DListNode *pos){
pos->_prev->_next = pos->_next ;
pos->_next->_prev=pos->_prev;
free(pos);
}
2.12 双链表的头删
- 1.定义一个指向双链表头结点的指针cur
- 2.让双链表头指针指向该指针(cur)所指向结点的下一个结点
- 3.释放cur所指向的结点空间
- 4.让头结点的prev指针指向NULL
void DListPopFront(DList *dlist){
assert(dlist!=NULL);
DListNode* cur=dlist->head;
dlist->head=cur->_next;
free(cur);
dlist->head->_prev=NULL;
}
2.12:双链表的尾删
- 1.定义一个指向双链表头结点的指针cur
- 2.让指针不断的往后移动,直到cur指向该链表的最后一个结点位置
- 3.将尾节点的prev指针指向结点的next指针指向NULL
- 4.释放cur所指的空间(原有的尾结点)
void DListPopBack(DList *dlist){
assert(dlist!=NULL);
DListNode* cur=dlist->head;
while(cur->_next!=NULL){
cur=cur->_next;
}
cur->_prev->_next=NULL;
free(cur);
}
3.源代码链接
C语言版的源代码