typedef int elemtype;
typedef struct Dlink
{
elemtype data;
Dlink *prev;
Dlink *next;
}Dlink;
typedef struct{
int cursize;
Dlink *head;
}Dlinklist;
下面是
#include"Double_link.h"//循环链表一定要有头节点,并且循环链表的next域永远不会为NULL,所以在判断是不能用p->next==NULL来作为条件
Dlink *buynode(Dlink *pr, Dlink*nt)
{
Dlink *dp = (Dlink*)malloc(sizeof(Dlink));
if (dp) exit(1);
dp->prev = (pr == NULL) ? dp : pr;
dp->next = (nt == NULL) ? dp : nt;
return dp;
}
void init_Dlinklist(Dlinklist&mylist)
{
mylist.head = buynode();
mylist.cursize = 0;
}
void freenode(Dlink*p)
{
free(p);
p->next = p->prev = NULL;
}
void insert_item_prev(Dlinklist&mylist, Dlink *ptr, elemtype x)//在ptr地址之前插入节点,在循环链表中这个插入函数是后面所有函数的关键
{ //尾插可以通过next的调用从而实现用前插代替尾插
ptr->prev = buynode(ptr->prev, ptr);
ptr = ptr->prev;
ptr->prev->next=ptr;
ptr->data = x;
mylist.cursize += 1;
}
void push_back(Dlinklist&mylist, elemtype val)
{
insert_item_prev(mylist, mylist.head, val);//相当于在头节点之前插入
}
void push_front(Dlinklist&mylist, elemtype val)
{
insert_item_prev(mylist, mylist.head->next, val);//相当于在头节点之后的节点的前面插入
}
void insert_next(Dlinklist&mylist, int size, elemtype x)//尾部插入size个x的值
{
int i = 1;
while (i++ <= size)
{
push_back(mylist, x);
}
}
void insert_array(Dlinklist&mylist,const elemtype *first,const elemtype *last)//first是首元素地址,last是数组末尾元素地址,可以用ar和ar+n来实现
{ //传参是insert_array(mylist,ar,ar+n)
assert(first == NULL || last == NULL);//断言 //在这个函数在ar+n是相当于指向了数组之后的那个地址,而不是数组最后一个元素地址
while (first != last){
push_back(mylist, *first);
first++;
}
}
void insertpos(Dlinklist&mylist, int pos, elemtype val)//按照位置插入
{
if (pos<1 || pos>mylist.cursize) return;
int i = 1;
Dlink *p = mylist.head->next;
while (i < pos)
{
p = p->next;
++i;
}
insert_item_prev(mylist, p, val);
}
void printlist(Dlinklist&mylist)
{
Dlink *p = mylist.head->next;
while (p != mylist.head)
{
cout << p->data;
}
}
Dlink *findpos(Dlinklist&mylist, int pos)//按位查找
{
if (pos<1 || pos>mylist.cursize) return NULL;
int i = 1;
Dlink *p = mylist.head->next;
while (i < pos)
{
p = p->next;
++i;
}
return p;
}
Dlink *findvalue(Dlinklist&mylist, elemtype val)//按值查找
{
Dlink *p = mylist.head->next;
while (p != mylist.head&&p->data != val)
{
p = p->next;
}
if (p == mylist.head) p = NULL;//一定要有这一步,应为查不到是p的值会返回到head
return p;
}
void eraseDlink(Dlinklist&mylist, Dlink *ptr)//删除节点
{
assert(ptr != NULL);
ptr->prev->next = ptr->next;
ptr->next->prev = ptr->prev;
freenode(ptr);
mylist.cursize -= 1;
}
int getsize(Dlinklist&mylist)
{
return mylist.cursize;
}
bool is_Empty(Dlinklist&mylist)
{
return mylist.cursize == 0;
}
void pop_front(Dlinklist&mylist)//头删
{
if (is_Empty(mylist)) return;
eraseDlink(mylist, mylist.head->next);
}
void pop_back(Dlinklist&mylist)
{
if (is_Empty(mylist)) return;
eraseDlink(mylist, mylist.head->prev);
}
void erasepos(Dlinklist&mylist, int pos)
{
if (is_Empty(mylist)) return;
Dlink *ptr = findpos(mylist, pos);
eraseDlink(mylist, ptr);
}
void remove(Dlinklist&mylist, elemtype val)//双循环链表在删除时比单链表方便,他可以进行前驱操作,从而减少一个指针使用
{
if (is_Empty(mylist)) return;
Dlink*p = mylist.head->next;
while (p!= mylist.head)
{
if (p->data == val)
{
p = p->next;
eraseDlink(mylist, p->prev);
}
else p = p->next; //之所以要加else是因为如果需要删除的数是一个连续的值,那么如果不加else,会将p的地址向后移动从而不检查p本身的data数据
}
}
void reverseDlinklist(Dlinklist&mylist)//逆置
{
if (mylist.cursize < 2) return;//节点数目少于2时不交换
Dlink *p = mylist.head->next;
while (p != mylist.head)
{
Dlink *s = p;
p = p->next;
swap(s->next, s->prev);//将节点的前驱和后继逆置
}
Dlink *tmp = p;
swap(tmp->next, tmp->prev);//当交换一圈后p指针回到头节点时,需要将头节点的前后指针互换
}
c语言双链表
最新推荐文章于 2024-07-04 11:06:26 发布