单链表的结点都只有一个指向下一个结点的指针

单链表的数据元素无法直接访问其前驱元素

逆序访问单链表中的元素是极其耗时的操作!

len = LinkList_Length(list);

for (i=len-1; len>=0; i++) //O(n)

{

LinkListNode *p = LinkList_Get(list, i); //O(n)

//访问数据元素p中的元素

//

}

双向链表的定义

在单链表的结点中增加一个指向其前驱的pre指针

插入操作异常处理

插入第一个元素异常处理

在0号位置处插入元素;

删除操作

删除操作异常处理

双向链表的新操作

获取当前游标指向的数据元素

将游标重置指向链表中的第一个数据元素

将游标移动指向到链表中的下一个数据元素

将游标移动指向到链表中的上一个数据元素

直接指定删除链表中的某个数据元素

DLinkListNode* DLinkList_DeleteNode(DLinkList* list, DLinkListNode* node);

DLinkListNode* DLinkList_Reset(DLinkList* list);

DLinkListNode* DLinkList_Current(DLinkList* list);

DLinkListNode* DLinkList_Next(DLinkList* list);

DLinkListNode* DLinkList_Pre(DLinkList* list);

循环链表插入结点技术场景

循环链表删除结点技术场景

优点和缺点

优点:双向链表在单链表的基础上增加了指向前驱的指针

功能上双向链表可以完全取代单链表的使用

双向链表的Next,Pre和Current操作可以高效的遍历链表中的所有元素

缺点:代码复杂

02 08 10

#ifndef _MY_DLINKLIST_H_
#define _MY_DLINKLIST_H_ typedef void DLinkList;
/*
typedef struct _tag_DLinkListNode DLinkListNode;
struct _tag_DLinkListNode
{
DLinkListNode* next;
DLinkListNode* pre;
};
*/ typedef struct _tag_DLinkListNode
{
struct _tag_DLinkListNode* next;
struct _tag_DLinkListNode * pre;
}DLinkListNode; DLinkList* DLinkList_Create(); void DLinkList_Destroy(DLinkList* list); void DLinkList_Clear(DLinkList* list); int DLinkList_Length(DLinkList* list); int DLinkList_Insert(DLinkList* list, DLinkListNode* node, int pos); DLinkListNode* DLinkList_Get(DLinkList* list, int pos); DLinkListNode* DLinkList_Delete(DLinkList* list, int pos); //-- add
DLinkListNode* DLinkList_DeleteNode(DLinkList* list, DLinkListNode* node); DLinkListNode* DLinkList_Reset(DLinkList* list); DLinkListNode* DLinkList_Current(DLinkList* list); DLinkListNode* DLinkList_Next(DLinkList* list); DLinkListNode* DLinkList_Pre(DLinkList* list); #endif
#include <stdio.h>
#include <malloc.h>
#include "DLinkList.h" typedef struct _tag_DLinkList
{
DLinkListNode header;
DLinkListNode* slider;
int length;
} TDLinkList; DLinkList* DLinkList_Create()
{
TDLinkList* ret = (TDLinkList*)malloc(sizeof(TDLinkList)); if( ret != NULL )
{
ret->length = ;
ret->header.next = NULL;
ret->header.pre = NULL;
ret->slider = NULL;
} return ret;
} void DLinkList_Destroy(DLinkList* list)
{
if (list != NULL)
{
free(list);
}
} void DLinkList_Clear(DLinkList* list)
{
TDLinkList* sList = (TDLinkList*)list; if( sList != NULL )
{
sList->length = ;
sList->header.next = NULL;
sList->header.pre = NULL;
sList->slider = NULL;
}
} int DLinkList_Length(DLinkList* list)
{
TDLinkList* sList = (TDLinkList*)list;
int ret = -; if( sList != NULL )
{
ret = sList->length;
} return ret;
} //大家一定要注意:教科书不会告诉你 项目上如何用;哪些点是项目的重点
int DLinkList_Insert(DLinkList* list, DLinkListNode* node, int pos)
{
int ret = , i = ;
TDLinkList* sList = (TDLinkList*)list; if (list==NULL || node==NULL || pos<)
{
return -;
} DLinkListNode* current = (DLinkListNode*)sList;
DLinkListNode* next = NULL; //需要增加next指针 for(i=; (i<pos) && (current->next != NULL); i++)
{
current = current->next;
} next = current->next; //步骤1-2
current->next = node;
node->next = next; //步骤3-4
if( next != NULL ) //当链表插入第一个元素,需要特殊处理
{
next->pre = node;
}
node->pre = current; if( sList->length == )
{
sList->slider = node; //当链表插入第一个元素处理游标
} //若在0位置插入,需要特殊处理 新来结点next前pre指向null
if( current == (DLinkListNode*)sList )
{
node->pre = NULL;
} sList->length++; return ret;
} DLinkListNode* DLinkList_Get(DLinkList* list, int pos)
{
TDLinkList* sList = (TDLinkList*)list;
DLinkListNode* ret = NULL;
int i = ; if( (sList != NULL) && ( <= pos) && (pos < sList->length) )
{
DLinkListNode* current = (DLinkListNode*)sList; for(i=; i<pos; i++)
{
current = current->next;
} ret = current->next;
} return ret;
} //插入第一个节点
//删除的是最后一个结点,该是如何处理
DLinkListNode* DLinkList_Delete(DLinkList* list, int pos)
{
TDLinkList* sList = (TDLinkList*)list;
DLinkListNode* ret = NULL;
int i = ;
if (sList == NULL || pos < )
{
return NULL;
}
//if( (sList != NULL) && (0 <= pos) && (pos < sList->length) )
{
DLinkListNode* current = (DLinkListNode*)sList;
DLinkListNode* next = NULL; //需要增加next指针 for(i=; i<pos; i++)
{
current = current->next;
} ret = current->next;
next = ret->next; //步骤1
current->next = next; //步骤2
if( next != NULL )//需要特殊处理
{
next->pre = current; if( current == (DLinkListNode*)sList ) //若第0个位置,需要特殊处理
{
next->pre = NULL;
}
} if( sList->slider == ret )
{
sList->slider = next;
} sList->length--;
} return ret;
} DLinkListNode* DLinkList_DeleteNode(DLinkList* list, DLinkListNode* node)
{
TDLinkList* sList = (TDLinkList*)list;
DLinkListNode* ret = NULL;
int i = ; if( sList != NULL )
{
DLinkListNode* current = (DLinkListNode*)sList; for(i=; i<sList->length; i++)
{
if( current->next == node )
{
ret = current->next;
break;
} current = current->next;
} if( ret != NULL )
{
DLinkList_Delete(sList, i);
}
} return ret;
} DLinkListNode* DLinkList_Reset(DLinkList* list)
{
TDLinkList* sList = (TDLinkList*)list;
DLinkListNode* ret = NULL; if( sList != NULL )
{
sList->slider = sList->header.next;
ret = sList->slider;
} return ret;
} DLinkListNode* DLinkList_Current(DLinkList* list)
{
TDLinkList* sList = (TDLinkList*)list;
DLinkListNode* ret = NULL; if( sList != NULL )
{
ret = sList->slider;
} return ret;
} DLinkListNode* DLinkList_Next(DLinkList* list)
{
TDLinkList* sList = (TDLinkList*)list;
DLinkListNode* ret = NULL; if( (sList != NULL) && (sList->slider != NULL) )
{
ret = sList->slider;
sList->slider = ret->next;
} return ret;
} DLinkListNode* DLinkList_Pre(DLinkList* list)
{
TDLinkList* sList = (TDLinkList*)list;
DLinkListNode* ret = NULL; if( (sList != NULL) && (sList->slider != NULL) )
{
ret = sList->slider;
sList->slider = ret->pre;
} return ret;
}
#include <stdio.h>
#include <stdlib.h>
#include "DLinkList.h" struct Value
{
DLinkListNode node;
int v;
}; int main()
{
int i = ;
DLinkList* list = DLinkList_Create();
struct Value* pv = NULL;
struct Value v1, v2, v3, v4, v5; v1.v = ; v2.v = ; v3.v = ; v4.v = ;
v5.v = ; DLinkList_Insert(list, (DLinkListNode*)&v1, DLinkList_Length(list));
DLinkList_Insert(list, (DLinkListNode*)&v2, DLinkList_Length(list));
DLinkList_Insert(list, (DLinkListNode*)&v3, DLinkList_Length(list));
DLinkList_Insert(list, (DLinkListNode*)&v4, DLinkList_Length(list));
DLinkList_Insert(list, (DLinkListNode*)&v5, DLinkList_Length(list)); for(i=; i<DLinkList_Length(list); i++)
{
pv = (struct Value*)DLinkList_Get(list, i); printf("%d\n", pv->v);
} printf("\n"); DLinkList_Delete(list, DLinkList_Length(list)-);
DLinkList_Delete(list, );
//DLinkList_Delete(list, 3); for(i=; i<DLinkList_Length(list); i++)
{
pv = (struct Value*)DLinkList_Next(list); printf("%d\n", pv->v);
} printf("\n"); DLinkList_Reset(list);
DLinkList_Next(list); pv = (struct Value*)DLinkList_Current(list); printf("%d\n", pv->v); DLinkList_DeleteNode(list, (DLinkListNode*)pv); pv = (struct Value*)DLinkList_Current(list); printf("%d\n", pv->v); DLinkList_Pre(list); pv = (struct Value*)DLinkList_Current(list); printf("%d\n", pv->v); printf("Length: %d\n", DLinkList_Length(list)); DLinkList_Destroy(list);
system("pause");
return ;
}

C 双向链表的更多相关文章

  1. 学习Redis你必须了解的数据结构——双向链表(JavaScript实现)

    本文版权归博客园和作者吴双本人共同所有,转载和爬虫请注明原文链接 http://www.cnblogs.com/tdws/ 下午分享了JavaScript实现单向链表,晚上就来补充下双向链表吧.对链表 ...

  2. 双向链表、双向循环链表的JS实现

    关于链表简介.单链表.单向循环链表.JS中的使用以及扩充方法:  单链表.循环链表的JS实现 关于四种链表的完整封装: https://github.com/zhuwq585/Data-Structu ...

  3. 剑指Offer面试题:25.二叉搜索树与双向链表

    一.题目:二叉搜索树与双向链表 题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向.比如输入下图中左边的二叉搜索树,则输出转换之后的 ...

  4. Linux 内核数据结构:Linux 双向链表

    Linux 内核提供一套双向链表的实现,你可以在 include/linux/list.h 中找到.我们以双向链表着手开始介绍 Linux 内核中的数据结构 ,因为这个是在 Linux 内核中使用最为 ...

  5. Linux 内核数据结构:双向链表

    Linux 内核提供一套双向链表的实现,你可以在 include/linux/list.h 中找到.我们以双向链表着手开始介绍 Linux 内核中的数据结构 ,因为这个是在 Linux 内核中使用最为 ...

  6. 线性表-双向链表(LinkedList)

    双向链表:如图1-3 所示,会把当前header拆分开,重新插入一个Entry<E>. LinkedList源码 0.首先这个类中的两个变量 private transient Entry ...

  7. Shuffling Machine和双向链表

    1. 双向链表 https://github.com/BodhiXing/Data_Structure 2. Shuffling Machine https://pta.patest.cn/pta/t ...

  8. MS - 1 - 把二元查找树转变成排序的双向链表

    ## 1. 把二元查找树转变成排序的双向链表 ## ### 题目: 输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表. ### 要求不能创建任何新的结点,只调整指针的指向. 10       ...

  9. javascript中的链表结构—双向链表

    1.概念 上一个文章里我们已经了解到链表结构,链表的特点是长度不固定,不用担心插入新元素的时候新增位置的问题.插入一个元素的时候,只要找到插入点就可以了,不需要整体移动整个结构. 这里我们了解一下双向 ...

  10. Java自己实现双向链表LinkList

    /** * <p> * Node 双向链表实体类 * <p> * * @author <a href="mailto:yangkj@corp.21cn.com& ...

随机推荐

  1. angularjs filter 详解

    系统的学习了一下angularjs,发现angularjs的有些思想根php的模块smarty很像,例如数据绑定,filter.如果对smarty比较熟悉的话,学习angularjs会比较容易一点.这 ...

  2. 先前设定的sa密码忘记了,如何修改sa密码?

    在window身份验证登陆后,新建查询,输入以下代码就可以修改sa密码了: use master go exec sp_password null,'123456','sa' go

  3. JVM内存结构之一--总体介绍

    Java 虚拟机在执行Java程序的时候会把它管理的内存区域划为几部分,这一节我们就来解析一下Java的内存区域. 有的人把JVM管理的内存简单地分为堆内存和栈内存,这样分未免有些太肤浅了. Java ...

  4. POJ 1151 Atlantis 线段树+离散化+扫描线

    这次是求矩形面积并 /* Problem: 1151 User: 96655 Memory: 716K Time: 0MS Language: G++ Result: Accepted */ #inc ...

  5. HDU 3533 Escape BFS搜索

    题意:懒得说了 分析:开个no[100][100][1000]的bool类型的数组就行了,没啥可说的 #include <iostream> #include <cstdio> ...

  6. 关于.jar的文件在cmd中无法连接数据库的问题

    我使用一个.jar的文件,想在cmd中以“java -jar *.jar”的格式运行,方便system.println()一些信息,该jar包中包含数据库连接内容,在我关闭comodo防火墙和wind ...

  7. 中文Win7下成功安装calabash-android步骤

    Calabash-android是支持android的UI自动化测试框架,网上看见很多同学说,安装calabash比较费劲,特别是Windows下安装,也没有一个详细的安装手册可供参考.正好,今天在W ...

  8. 树莓PI安装jdk1.8,ant,maven【转】

    http://the.taoofmac.com/space/hw/RaspberryPi/JDK%20Installation jdk--------------------------------- ...

  9. Ubuntu 14.04 设置静态IP

    使用Network Manager UI界面中指定 手动时,无法保存. 通过修改配置文件解决来此问题.记录以下. 如果输入过密码后,就会出现在这个目录下面, 以如下chinaNet为例 gaojing ...

  10. ubuntu 中文界面下中文文件夹改英文

    首先,打开终端,切换成英文环境, export LANG=en_US   接着,目录转换 xdg-user-dirs-gtk-update   最后,切换回中文环境 export LANG=zh_CN ...