C 双向链表
单链表的结点都只有一个指向下一个结点的指针 单链表的数据元素无法直接访问其前驱元素 逆序访问单链表中的元素是极其耗时的操作! |
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 双向链表的更多相关文章
- 学习Redis你必须了解的数据结构——双向链表(JavaScript实现)
本文版权归博客园和作者吴双本人共同所有,转载和爬虫请注明原文链接 http://www.cnblogs.com/tdws/ 下午分享了JavaScript实现单向链表,晚上就来补充下双向链表吧.对链表 ...
- 双向链表、双向循环链表的JS实现
关于链表简介.单链表.单向循环链表.JS中的使用以及扩充方法: 单链表.循环链表的JS实现 关于四种链表的完整封装: https://github.com/zhuwq585/Data-Structu ...
- 剑指Offer面试题:25.二叉搜索树与双向链表
一.题目:二叉搜索树与双向链表 题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向.比如输入下图中左边的二叉搜索树,则输出转换之后的 ...
- Linux 内核数据结构:Linux 双向链表
Linux 内核提供一套双向链表的实现,你可以在 include/linux/list.h 中找到.我们以双向链表着手开始介绍 Linux 内核中的数据结构 ,因为这个是在 Linux 内核中使用最为 ...
- Linux 内核数据结构:双向链表
Linux 内核提供一套双向链表的实现,你可以在 include/linux/list.h 中找到.我们以双向链表着手开始介绍 Linux 内核中的数据结构 ,因为这个是在 Linux 内核中使用最为 ...
- 线性表-双向链表(LinkedList)
双向链表:如图1-3 所示,会把当前header拆分开,重新插入一个Entry<E>. LinkedList源码 0.首先这个类中的两个变量 private transient Entry ...
- Shuffling Machine和双向链表
1. 双向链表 https://github.com/BodhiXing/Data_Structure 2. Shuffling Machine https://pta.patest.cn/pta/t ...
- MS - 1 - 把二元查找树转变成排序的双向链表
## 1. 把二元查找树转变成排序的双向链表 ## ### 题目: 输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表. ### 要求不能创建任何新的结点,只调整指针的指向. 10 ...
- javascript中的链表结构—双向链表
1.概念 上一个文章里我们已经了解到链表结构,链表的特点是长度不固定,不用担心插入新元素的时候新增位置的问题.插入一个元素的时候,只要找到插入点就可以了,不需要整体移动整个结构. 这里我们了解一下双向 ...
- Java自己实现双向链表LinkList
/** * <p> * Node 双向链表实体类 * <p> * * @author <a href="mailto:yangkj@corp.21cn.com& ...
随机推荐
- BZOJ_1022_[SHOI2008]_小约翰的游戏John_(博弈论_反Nim游戏)
描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1022 反Nim游戏裸题.详见论文<组合游戏略述——浅谈SG游戏的若干拓展及变形>. ...
- Self-Paced Training (2) - Docker Fundamentals
Agenda- Building Images Dockerfile Managing Images and Containers Distributing Images on Docker Hub ...
- 修改Android默认背光值
/********************************************************************* * 修改Android默认背光值 * 说明: * 本文主要 ...
- 【转】经典SQL语句大全
原博客地址:http://www.cnblogs.com/yubinfeng/archive/2010/11/02/1867386.html (超级纳闷为啥没有转载的功能) 一.基础 1.说明:创建数 ...
- java泛型小总结
一. 泛型概念的提出(为什么需要泛型)? 首先,我们看下下面这段简短的代码: public class GenericTest { public static void main(String[] a ...
- C#打印100以内质数
bool b = false; ; i < ; i++) { ; j < i; j++) { ) { b = false; break; } else { b = true; } } if ...
- 《Data-Intensive Text Processing with mapReduce》读书笔记之一:前言
暑假闲得蛋痒,混混沌沌,开始看<Data-Intensive Text Processing with mapReduce>,尽管有诸多单词不懂,还好六级考多了,虽然至今未过:再加上自己当 ...
- n & (n-1)
n&(n-1)作用:将n的二进制表示中的最低位为1的改为0,先看一个简单的例子: n = 10100(二进制),则(n-1) = 10011 ==>n&(n-1) = 10000 ...
- Python几个算法实现
1.平衡点问题: 比如int[] numbers = {1,3,5,7,8,25,4,20}; 25前面的总和为24,25后面的总和也是24,25这个点就是平衡点:假如一个数组中的元素,其前面的部分等 ...
- [iOS基础控件 - 5.1] UIScrollView
A.需要掌握 UIScrollView 是一个能够滚动的视图控件,可以用来展示大量内容,如手机的“设置” 1.常见属性 2.常用代理方法 3.缩放 4.UIScrollView和UIPageContr ...