双向链表介绍:
双向循环链表在单链表的基础上,每个节点添加一个指针域,这个指针域指向前一个节点。对于双向循环链表的任何一个节点,都可以往前/往后访问,往前和往后访问的效率相同。双向循环链表付出多维护一个指针域的代价,带来了访问效率的提高和平稳。
空双向循环链表
双向循环链表
双向链表节点
typedef int T;
//节点类型
typedef struct node{
T data;//数据域
struct node *prev;//前置指针
struct node *next;//后置指针
}dnode_t,*dlist_t;
C代码实现
- 创建空链表
dlist_t create_emptydlist()
{
//申请空间
dlist_t head = (dlist_t)malloc(sizeof(dnode_t));
if(head)
{
//head->data = -1;
//空链表头节点的前置和后置指针都指向自己
head->prev = head;
head->next = head;
}
return head;
}
- 增加节点
成功返回新插入节点的地址,失败返回NULL
//往指定位置之后插入一个节点
static dlist_t insert(dlist_t p,T dt)
{
//构造新节点
dlist_t newnode = (dlist_t)malloc(sizeof(dnode_t));
if(newnode)
{
newnode->data = dt;
//新节点的前置指针指向插入的位置
newnode->prev = p;
//新节点的后置指针指向插入位置的下一个节点
newnode->next = p->next;
//插入位置节点的后置指针指向新节点
p->next = newnode;
//插入位置的后一个节点的前置指针指向新节点
newnode->next->prev = newnode;
}
return newnode;
}
//从头部插入
dlist_t insert_from_head(dlist_t head,T dt)
{
return insert(head,dt);
}
//从尾部插入
dlist_t insert_from_tail(dlist_t head,T dt)
{
return insert(head->prev,dt);
}
- 查找节点
成功返回节点地址,失败返回NULL
//按位置查找
dlist_t find_by_index(dlist_t head,int index)
{
int i = 1;
dlist_t p = head->next;
while(p!=head){
if(i==index)
return p;
p = p->next;
i++;
}
return NULL;
}
//按值查找
dlist_t find_by_value(dlist_t head,T dt)
{
dlist_t p = head->next;
while(p!=head){
if(p->data==dt)
return p;
p = p->next;
}
return NULL;
}
- 删除节点
成功返回0,失败返回-1
//按位置删除
int delete_by_index(dlist_t head,int index)
{
//1.找到要删除的节点
dlist_t del_node = find_by_index(head,index);
if(!del_node)
return -1;
//2.删除该节点
//将删除节点的前一个节点的后置指针改为指向删除节点的后一个节点
del_node->prev->next = del_node->next;
//将删除节点的后一个节点的前置指针改为指向删除节点的前一个节点
del_node->next->prev = del_node->prev;
//释放删除节点
free(del_node);
del_node = NULL;
return 0;
}
//按值删除
int delete_by_value(dlist_t head,T dt)
{
//1.找到要删除的节点
dlist_t del_node = find_by_value(head,dt);
if(!del_node)
return -1;
//2.删除该节点
//将删除节点的前一个节点的后置指针改为指向删除节点的后一个节点
del_node->prev->next = del_node->next;
//将删除节点的后一个节点的前置指针改为指向删除节点的前一个节点
del_node->next->prev = del_node->prev;
//释放删除节点
free(del_node);
del_node = NULL;
return 0;
}
- 排序
void sort(dlist_t head)
{
dlist_t p = head->next,k = NULL,q = NULL; //p 指向未排序部分
//将链表置空
head->next = head;
head->prev = head;
//遍历p,依次插入结点
while(p!=head)
{
k = p->next;
q = head->next;//排好序的部分
//找到p插入的位置
while(1)
{
//插入的节点p比当前节点q的值小,直接插入该节点q之前
if(q==head||p->data<=q->data)
{
p->prev = q->prev;
p->next = q;
q->prev->next = p; //q的值已经往后移动了
q->prev = p; //
break;
}
q = q->next;
}
//如果遍历完排好序的所有节点都没有找到插入的位置,说明插入的节点p的值最大,p插入head之前
/*if(q==head){
p->prev = head->prev;
p->next = head;
head->prev->next = p;
head->prev = p;
}*/
p = k;//准备插入下一个
}
}
- 遍历链表
void travel(dlist_t head)
{
dlist_t p = head->next;
//回到头节点遍历结束
while(p!=head){
printf("%d ",p->data);
p = p->next;
}
printf("\n");
}
- 清空链表
void clear(dlist_t head)
{
dlist_t p = head->next,q = NULL;
//让头节点的指针域指向自己
head->next = head;
head->prev = head;
//释放节点
while(p!=head){
q = p;
p = p->next;
free(q);
}
p = q = NULL;
}
- 销毁链表
void destroy(dlist_t *phead)
{
clear(*phead);
free(*phead);
*phead = NULL;
}