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

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

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

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. bzoj1433:[ZJOI2009]假期的宿舍

    明显的二分图最大匹配. #include<cstdio> #include<cstring> #include<cctype> #include<algori ...

  2. 8.3-8.7 usaco

    summary:38 vijos1002:青蛙跳河. dp+压缩.距离大于100可以直接%100.然后数据范围小了很多可以dp了. #include<cstdio> #include< ...

  3. C# List 用法与示例

    Problem. You have questions about the List collection in the .NET Framework, which is located in the ...

  4. Java泛型类与类型擦除

    转载自:http://blog.csdn.net/lonelyroamer/article/details/7868820 一.Java泛型的实现方法:类型擦除 前面已经说了,Java的泛型是伪泛型. ...

  5. Rman实现数据库迁移

    Rman实现数据库迁移(从库A迁移到库B)环境:服务器A:Oracle10g+AS3服务器B:Oracle10g+AS4准备工作: 1 在数据库B上建立与库A相同的目录结构(若由于磁盘空间等原因可以用 ...

  6. 数组中所有重复次数大于等于minTimes的数字

    class Program { static void Main(string[] args) { int[] input = { 1, 1, 1, 2, 2, 5, 2, 4, 9, 9, 20 } ...

  7. Eclipse文件编码设置的问题

    Eclipse中设置编码的方式 如果要使插件开发应用能有更好的国际化支持,能够最大程度的支持中文输出, 则最好使 Java文件使用UTF-8编码.然而,Eclipse工作空间(workspace)的缺 ...

  8. 错误 1 在应用程序级别之外使用注册为 allowDefinition='

    原文:错误 1 在应用程序级别之外使用注册为 allowDefinition='MachineToApplication' 的节是错误的,银流沙 昨天运行一个.NET网站项目时,出现了以下问题: 在应 ...

  9. 转载--PHP json_encode() 和json_decode()函数介绍

    转自:http://www.nowamagic.net/php/php_FunctionJsonEncode.php 转自:http://www.jb51.net/article/30489.htm ...

  10. HDU5593 ZYB's Tree 树形DP +分治

    感觉其实就是树分治,一次BC的题,感觉这次题目质量比较高,仅代表蒟蒻的看法 一次DFS获取每个点到子树的距离不大于K的点的个数, 然后一遍BFS获取从每个点父亲不大于K的的个数,层层扩展,还是想说 其 ...