C语言 有序双链表实现插入、删除、打印(正反)等简单操作
2018-01-12 22:45
423 查看
1.双链表与单链表的区别主要是在于双链表中,每个节点都包含两个指针——指向前一个节点的指针,和指向后一个节点的指针。这就便于我们从任何方向遍历整个链表。
下面是节点类型的说明:
构造了一个简单的链表节点,此时,我们需要两个根指针,一个指向链表的第一个节点,另一个指向链表的最后一个节点。
我们可以考虑为根指针声明一个完整的节点,但应该注意其value字段不被使用,我们仅仅是用该节点来表示根指针,其并不存在于链表之中,我们让rootp->fwd表示链表第一个节点,而rootp->指向链表最后一个节点,这就需要在main函数中为该节点分配空间,且初始化rootp->fwd以及rootp->bwd为NULL。
这时可以在专门的free函数中释放该空间,也可以在main函数最后释放。
2.实现值的有序插入
这时需要考虑节点插入的位置,一般来讲有4种情况:
1.插入位置在链表中间段;
2.插入位置在链表初始段;
3.插入位置在链表尾部;
4.该链表为空链表;
需要分别考虑这4种不同情况下节点的fwd及bwd指针指向。
以下代码详细描述了这四种情况下的指针指向:
同时,我们可以注意到以上单纯实现插入的代码段比较冗余,由于if语句内有功能相似或相同的代码,我们可以将其提取出现,减少代码量。
比如每个if语句中都有newnode->fwd=next,以及this->fwd=newnode.且在程序运行到该段时,newnode及this指针一定不为NULL,故可以直接提取出来。如下是改进后的完整的插入节点的代码段。
ps:注意到根指针rootp的存储空间是在main函数中通过malloc语句分配,存储在堆(heap)中,在做插入、删除等系列操作时,并不需要改变rootp的值,故在函数参数列表中并不需要像单链表头指针一样传入其地址(当然,传地址也是可以的)。
这里是直接将rootp的值传入到函数中。
3.删除节点
在删除某个节点时,需要注意删除的位置是在初始位置,中间位置,还是末尾位置,同时需注意删除之后链表是否为空。
3.正向打印及反向打印
这个操作比较简单,不多做介绍。
下面是节点类型的说明:
typedef struct NODE{ struct NODE *fwd; struct NODE *bwd; int value; }Node;
构造了一个简单的链表节点,此时,我们需要两个根指针,一个指向链表的第一个节点,另一个指向链表的最后一个节点。
我们可以考虑为根指针声明一个完整的节点,但应该注意其value字段不被使用,我们仅仅是用该节点来表示根指针,其并不存在于链表之中,我们让rootp->fwd表示链表第一个节点,而rootp->指向链表最后一个节点,这就需要在main函数中为该节点分配空间,且初始化rootp->fwd以及rootp->bwd为NULL。
Node *rootp; rootp=(Node *)malloc(sizeof(Node)); //为根指针分配空间,并初始化链表第一部分为NULL rootp->bwd=NULL; rootp->fwd=NULL;
这时可以在专门的free函数中释放该空间,也可以在main函数最后释放。
2.实现值的有序插入
这时需要考虑节点插入的位置,一般来讲有4种情况:
1.插入位置在链表中间段;
2.插入位置在链表初始段;
3.插入位置在链表尾部;
4.该链表为空链表;
需要分别考虑这4种不同情况下节点的fwd及bwd指针指向。
以下代码详细描述了这四种情况下的指针指向:
if(next!=NULL) //四种情况 { //1.中间 2.起始 3.末尾 4.空 if(this!=rootp) //1.中间 { newnode->fwd=next; this->fwd=newnode; next->bwd=newnode; newnode->bwd=this; } else{ //2.初始 newnode->fwd=next; rootp->fwd=newnode; newnode->bwd=NULL; next->bwd=newnode; } } else{ if(this!=rootp) //末尾非空 { newnode->fwd=next; this->fwd=newnode; newnode->bwd=this; rootp->bwd=newnode; } else{ //空 newnode->fwd=NULL; rootp->fwd=newnode; newnode->bwd=NULL; rootp->bwd=newnode; } }
同时,我们可以注意到以上单纯实现插入的代码段比较冗余,由于if语句内有功能相似或相同的代码,我们可以将其提取出现,减少代码量。
比如每个if语句中都有newnode->fwd=next,以及this->fwd=newnode.且在程序运行到该段时,newnode及this指针一定不为NULL,故可以直接提取出来。如下是改进后的完整的插入节点的代码段。
ps:注意到根指针rootp的存储空间是在main函数中通过malloc语句分配,存储在堆(heap)中,在做插入、删除等系列操作时,并不需要改变rootp的值,故在函数参数列表中并不需要像单链表头指针一样传入其地址(当然,传地址也是可以的)。
这里是直接将rootp的值传入到函数中。
int dll_insert(Node *rootp,int num) { Node *next; //插入位置的下一个 Node *this; //插入位置的前一个 Node *newnode; // for(this=rootp;(next=this->fwd)!=NULL;this=next) for(this=rootp,next=rootp->fwd;next;this=next,next=next->fwd) //寻找插入位置,从头开始 { if(next->value==num) //插入不同数 return 0; else if(next->value>num) //一旦找到比待插入数大的位置,跳出循环; break; } newnode=(Node *)malloc(sizeof(Node)); //为新插入的节点分配空间 if(newnode==NULL) return -1; newnode->value=num; newnode->fwd=next; //以下是实现插入(简化版) this->fwd=newnode; if(this!=rootp) //非初始 { newnode->bwd=this; } else{ //初始 newnode->bwd=NULL; } if(next!=NULL) //非结尾 { next->bwd=newnode; } else{ //结尾(新加入的节点在最后一个位置) rootp->bwd=newnode; } return 1; }
3.删除节点
在删除某个节点时,需要注意删除的位置是在初始位置,中间位置,还是末尾位置,同时需注意删除之后链表是否为空。
void reduce(Node *rootp) //删除 { Node *q,*p,*t; //t可以木有√ int isFound=0; //标记是否找到 int num; puts("Please enter the num to delete:"); scanf("%d",&num); while(getchar()!='\n') continue; for(q=NULL,p=rootp->fwd;p;q=p,p=p->fwd) //删除 { if(p->value==num) //如果找到了 { isFound=1; if(q) { q->fwd=p->fwd; // if(p->fwd==NULL) //最后位置 { rootp->bwd=q; //表示q位置为最后一个,删除p; } else{ // t=p->fwd; //p->fwd->bwd=q; p->fwd->bwd=q; //不是最后一个,删除p,p的后一个的前一个为q } } else{ rootp->fwd=p->fwd; //q为NULL,那么p是第一个,删除p,根指针指向第二个(可能为空,这样整个链表就是空的了),现在是第一个了 if(p->fwd==NULL) //p是最后一个。说明删除之后就没有了 rootp->bwd=NULL; //整个链表为空, rootp->bwd=NULL rootp->fwd=p->fwd,而p->fwd为空 else{ p->fwd->bwd=NULL;//这个意思是p后面还有,那么该节点为第一个了,其bwd要指向NULL; } } free(p); break; } } if(!isFound) { printf("Not found.\n"); } }
3.正向打印及反向打印
这个操作比较简单,不多做介绍。
void print(Node *rootp) //打印 { Node *p; for(p=rootp->fwd;p;p=p->fwd) //正向打印,以根指针的初始指向为开始,以链表初始节点开始 { printf("The num is %d.\n",p->value); } } void bkprint(Node *rootp) //反向打印 { Node *p; for(p=rootp->bwd;p;p=p->bwd) //反向打印,以根指针的bwd为始,指向的是链表最后一个节点 { printf("The num is %d.\n",p->value); } }
相关文章推荐
- C语言实现双链表基本操作(创建、查找、插入、删除)
- 链表的基本操作(创建,查找指定位置元素,删除指定元素,插入,倒置,去重,求集合的差,分别交换结点与交换结点值实现的冒泡排序,将两个有序链表合并成一个有序链表)c语言实现
- [原]C语言实现双向链表删除节点、插入节点、双向输出等操作
- (C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作
- C语言实现双向链表删除节点、插入节点、双向输出等操作
- (C语言版)链表(四)——实现双向循环链表创建、插入、删除、释放内存等简单操作
- (C语言版)链表(四)——实现双向循环链表创建、插入、删除、释放内存等简单操作
- 单链表相关操作之C语言实现:插入,删除,倒转,复制,查找。。。
- (C语言版)链表(二)——实现单向循环链表创建、插入、删除、释放内存等简单操作
- 对线性表理解以及C语言实现链表的插入删除等操作。
- 学习笔记——C语言实现单链表的基本操作:创建、输出、插入结点、删除结点、逆序链表
- 数据结构 单链表插入删除操作(c语言实现)
- 如何使用c语言实现双向链表的插入删除操作
- c语言:顺序表的实现(一) 创建,插入,删除,查找,输出等基本操作实现
- C语言实现双向链表删除节点、插入节点、双向输出等操作
- (C++版)链表(四)——实现双向循环链表创建、插入、删除等简单操作
- 二叉查找树的查找、插入、删除、释放等基本操作的实现(C语言)
- C语言各种链表操作(创建、打印、删除、插入、反转)
- (C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作
- C语言实现带头结点的链表的创建、查找、插入、删除操作