您的位置:首页 > 其它

双向链表设计与API实现

2015-07-12 20:03 387 查看
为什么需要双向链表?

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

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

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

双向链表的定义

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



双向链表拥有单链表的所有操作

创建链表

销毁链表

获取链表长度

清空链表

获取第pos个元素操作

插入元素到位置pos

删除位置pos处的元素

插入操作



插入操作异常处理

插入第一个元素异常处理

在0号位置处插入元素;

删除操作



双向链表的新操作

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

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

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

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

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

双向链表重要技术场景



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



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



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

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

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

缺点:代码复杂

// dlinklist.h
// 双向链表API声明

#ifndef _DLINKLIST_H_
#define _DLINKLIST_H_

typedef void DLinkList;

typedef struct _tag_DLinkListNode
{
_tag_DLinkListNode *next;
_tag_DLinkListNode *pre;
}DLinkListNode;

// 创建链表
DLinkList* DLinkList_Create();

// 销毁链表
void DLinkList_Destroy(DLinkList *list);

// 清空链表
void DLinkList_Clear(DLinkList *list);

// 获取链表长度
int DLinkList_Length(DLinkList *list);

// 在pos位置,插入结点node
int DLinkList_Insert(DLinkList *list, DLinkListNode *node, int pos);

// 获取pos位置的结点,返回给上层
DLinkListNode* DLinkList_Get(DLinkList *list, int pos);

// 删除pos位置的结点
DLinkListNode* DLinkList_Delete(DLinkList *list, int pos);

// 删除值为node的结点
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


// dlinklist.cpp
// 循环链表API实现

#include <cstdio>
#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->header.next = NULL;
ret->header.pre = NULL;
ret->slider = NULL;
ret->length = 0;
}

return ret;
}

// 销毁链表
void DLinkList_Destroy(DLinkList *list)
{
if (list != NULL) {
free(list);
}

return;
}

// 清空链表
void DLinkList_Clear(DLinkList *list)
{
TDLinkList *tList = (TDLinkList *)list;

if (tList != NULL) {
tList->header.next = NULL;
tList->header.pre = NULL;
tList->slider = NULL;
tList->length = 0;
}

return;
}

// 获取链表长度
int DLinkList_Length(DLinkList *list)
{
TDLinkList *tList = (TDLinkList *)list;
int ret = -1;

if (tList != NULL) {
ret = tList->length;
}

return ret;
}

// 在pos位置,插入结点node
int DLinkList_Insert(DLinkList *list, DLinkListNode *node, int pos)
{
TDLinkList *tList = (TDLinkList *)list;
int ret = -1, i = 0;

if (list != NULL && node != NULL && pos >= 0)
{
ret = 0;

DLinkListNode *cur = (DLinkListNode *)tList;
DLinkListNode *next = NULL;

for (i = 0; i < pos && cur->next != NULL; ++i) {
cur = cur->next;
}

next = cur->next;

cur->next = node;
node->next = next;

// 当链表插入第一个结点时需要进行特殊处理
if (next != NULL) {
next->pre = node;
}
node->pre = cur;

if (tList->length == 0)	 {
tList->slider = node; // 当链表插入第一个元素处理游标
}

// 若在0位置插入,需要特殊处理,新来的结点next前pre指向NULL
if (cur == (DLinkListNode *)tList) {
node->pre = NULL;
}
++tList->length;
}

return ret;
}

// 获取pos位置的结点,返回给上层
DLinkListNode* DLinkList_Get(DLinkList *list, int pos)
{
TDLinkList *tList = (TDLinkList *)list;
DLinkListNode* ret = NULL;
int i = 0;

if (list != NULL && pos >= 0 && pos < tList->length) {
DLinkListNode *cur = (DLinkListNode *)tList;

for (i = 0; i < pos; ++i) {
cur = cur->next;
}

ret = cur->next;
}

return ret;
}

// 删除pos位置的结点
DLinkListNode* DLinkList_Delete(DLinkList *list, int pos)
{
TDLinkList *tList = (TDLinkList *)list;
DLinkListNode* ret = NULL;
int	i = 0;

if (tList != NULL && pos >= 0) {
DLinkListNode *cur = (DLinkListNode *)tList;
DLinkListNode *next = NULL;

for (i = 0; i < pos && cur->next != NULL; ++i) {
cur = cur->next;
}

ret = cur->next;
next = ret->next;

cur->next = next;

if (next != NULL) {
next->pre = cur;

if (cur == (DLinkListNode *)tList) { // 第0个位置,需要特殊处理
next->pre = NULL;
}
}

if (tList->slider == ret) {
tList->slider = next;
}

--tList->length;
}

return ret;
}

// 删除值为node的结点
DLinkListNode* DLinkList_DeleteNode(DLinkList* list, DLinkListNode* node)
{
TDLinkList *tList = (TDLinkList *)list;
DLinkListNode* ret = NULL;
int	i = 0;

if (tList != NULL) {
DLinkListNode *cur = (DLinkListNode *)tList;

for (i = 0; i < DLinkList_Length(tList); ++i) {
if (cur->next == node) {
ret = cur->next;
break;
}

cur = cur->next;
}

if (!ret) {
DLinkList_Delete(tList, i);
}
}

return ret;
}

// 重置游标
DLinkListNode* DLinkList_Reset(DLinkList* list)
{
TDLinkList *tList = (TDLinkList *)list;
DLinkListNode* ret = NULL;

if (tList != NULL) {
tList->slider = tList->header.next;
ret = tList->slider;
}

return ret;
}

// 获取当前游标所指的结点
DLinkListNode* DLinkList_Current(DLinkList* list)
{
TDLinkList *tList = (TDLinkList *)list;
DLinkListNode* ret = NULL;

if (tList != NULL) {
ret = tList->slider;
}

return ret;
}

// 获取游标当前所指结点,然后让游标指向下一个结点
DLinkListNode* DLinkList_Next(DLinkList* list)
{
TDLinkList *tList = (TDLinkList *)list;
DLinkListNode* ret = NULL;

if (tList != NULL && tList->slider != NULL) {
ret = tList->slider;
tList->slider = ret->next;
}

return ret;
}

// 获取游标当前所指结点,然后让游标指向前一个结点
DLinkListNode* DLinkList_Pre(DLinkList* list)
{
TDLinkList *tList = (TDLinkList *)list;
DLinkListNode* ret = NULL;

if (tList != NULL && tList->slider != NULL) {
ret = tList->slider;
tList->slider = ret->pre;
}

return ret;
}


// main.cpp
// 循环线表测试程序

#include <cstdio>
#include "dlinklist.h"

const int maxn = 5;

struct Student
{
DLinkListNode node;
int age;
};

void play()
{
Student s[maxn];
for (int i = 0; i < maxn; ++i) {
s[i].age = i + 21;
}

DLinkList *list = NULL;
list = DLinkList_Create(); // 创建链表

// 插入结点
for (int i = 0; i < maxn; ++i) {
int ret = DLinkList_Insert(list, (DLinkListNode *)&s[i], DLinkList_Length(list));
if (ret < 0) {
return;
printf("function DLinkList_Insert err.\n");
}
}

// 遍历链表
for (int i = 0; i < DLinkList_Length(list); ++i) {
Student *tmp = (Student *)DLinkList_Get(list, i);
if (tmp == NULL) {
printf("function DLinkList_Get err.\n");
return;
}
printf("age: %d\n", tmp->age);
}

DLinkList_Delete(list, DLinkList_Length(list) - 1); // 删除尾结点
DLinkList_Delete(list, 0); // 删除头结点

// 用游标遍历链表
for (int i = 0; i < DLinkList_Length(list); ++i) {
Student *tmp = (Student *)DLinkList_Next(list);
if (tmp == NULL) {
printf("function DLinkList_Next err.\n");
return;
}
printf("age: %d\n", tmp->age);
}

printf("\n");

DLinkList_Reset(list);
DLinkList_Next(list);

Student *tmp = (Student *)DLinkList_Current(list);
if (tmp == NULL) {
printf("function DLinkList_Current err.\n");
return;
}
printf("age: %d\n", tmp->age);

DLinkList_DeleteNode(list, (DLinkListNode*)tmp);
tmp = (Student *)DLinkList_Current(list);
if (tmp == NULL) {
printf("function DLinkList_Current err.\n");
return;
}
printf("age: %d\n", tmp->age);
printf("length: %d\n", DLinkList_Length(list));

DLinkList_Pre(list);
tmp = (Student *)DLinkList_Current(list);
if (tmp == NULL) {
printf("function DLinkList_Current err.\n");
return;
}
printf("age: %d\n", tmp->age);

printf("length: %d\n", DLinkList_Length(list));
DLinkList_Destroy(list);

return;
}

int main()
{
play();

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: