双链表定义
双链表就是在单链表结点上增添了一个指针域,指向当前结点的前驱。这样就能够方便的由其后继来找到其前驱,而实现输出终端结点到开始结点的数据序列。php
一样,双链表也分为带头结点的双链表和不带头结点的双链表,状况相似于单链表。带头结点的双链表 head->next 为null的时候链表为空。不带头结点的双链表head为null的时候链表为空。node
1.采用尾插法创建双链表
void CreateDlistR (DLNode *&L, int a[], int n){ DLNode*s,*r; inti; L = (DLNode*)malloc(sizeof(DLNode)); L->next = NULL; //和单链表同样r始终指向终端结点,开始头结点也是尾结点 r = L; for(i = 1; i< = n; i++){ //建立新结点s->data = a[i]; s = (DLNode*)malloc(sizeof(DLNode)); /*下边3句将s插入在L的尾部而且r指向s,s->prior = r;这一句是和创建单链表不一样的地方。 */ r->next = s; s->prior = r; r = s; } r->next = NULL; }
2.查找结点的算法
在双链表中查找第一个结点值为x的结点。从第一个结点开始,边扫描边比较,若找到这样的结点,则返回结点指针,不然返回NULL。算法代码以下:算法
DLNode* Finfnode(DLNode *C, int x){
DLNode *p = C->next;
while(p != NULL){ if(p->data == x) { break; } p = p->next; } return p; //若是找到则p中内容是结点地址(循环因break结束), //没找到 p中内容是NULL(循环因p等于NULL而结束) //所以这一句能够将题干中要求的两种返回值的种状况统一。 }
3.插入结点的算法
假设在双链表中p所指的结点以后插入一个结点s,其操做语句描述为:ui
s->next = p->next; s->prior = p; p->next = s; s->next->prior = s;
指针变化过程如图:spa
若是按照上面的顺序来插入,能够当作是一个万能的插入方式。先将要插入的结点两边连接好,能够保证不会发生链断以后找不到结点的状况。指针
4.删除结点的算法
设要删除双链表中p结点的后继结点,其操做的语句为:code
q= p->next; p->next= q->next; q->next->prior= p; free(q);
指针变化过程如图所示:blog
循环单链表
只要将单链表的最后一个指针域(空指针)指向链表中第一个结点便可(这里之因此说第一个结点而不说是头结点是由于,若是循环单链表是带头结点的则最后一个结点的指针域要指向头结点;若是循环单链表不带头结点,则最后一个指针域要指向开始结点)。it
带头结点的循环单链表当head等于head->next时链表为空;
不带头结点的循环单链表当head等于null时链表为空。io
循环双链表
循环双链表的构造源自双链表,即将终端结点的nnext指针指向链表中第一个结点,将链表中第一个结点的prior指针指向终端结点。
带头结点的循环双链表当head->next和heaad->prior两个指针都等于head时链表为空。
不带头结点的循环双链表当head等于null的时候为空。
循环链表的算法操做
循环单链表和循环双链表由对应的单链表和双链表改造而来,只需在终端结点和头结点间创建联系便可。
循环单链表终端结点的next结点指针指向表头结点;循环双链表终端结点的next指针指向表头结点,头结点的prior指针指向表尾结点。
若是p指针沿着循环链表行走,判断p走到表尾结点的条件是p->next == head
。循环链表的各类操做均与非循环链表相似。