在学习RTOS操作系统时,在任务优先级设置时用到了双向链表,说实话数据结构的东西只是停留在大学上课阶段,并未实践过,在操作系统中看得云里雾里,遂将其单独拿来了进行了一下思考,经过一个上午的摸索逐渐领会到了其中的精华。

  1.什么是双向链表

百度百科:双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。

  

  此表中包含两个重要信息:链表结构,节点结构

  首先定义好节点的结构体:

 typedef struct _tNode
{
int data;
struct _tNode * pre;
struct _tNode * next;
}tNode;

然后在定义链表的结构体:

 typedef struct _tList
{
tNode HeadNode;
int NodeCount;
}tList;

  这个结构体的作用就是可以在工程中创建多个这样的链表结构,结构体里包含头结点HeadNode和此链表节点的数量NodeCount用来对链表进行操作的定位。头结点并不保存数据,只是提供指向节点的指针用来连接整个链表。所以在操作链表时可以很快地进行各种操作。在操作链表时只需要对完成对节点地添加和删除即可,头结点保持不变!

  基本初始化:

void tNodeInit(tNode *Node)
{
Node->pre = Node;
Node->next = Node;
} void tListInit(tList *list)//初始化链表
{
list->HeadNode.pre = &(list->HeadNode);
list->HeadNode.next = &(list->HeadNode);
list->NodeCount = ;
} int tListCount(tList *list)//返回链表节点数量
{
return list->NodeCount;
}

节点数据的插入和删除:

tNode* FirstNode(tList *list)//返回首节点
{
tNode* node = (tNode*);
if (list->NodeCount != )
{
node = list->HeadNode.next;
}
return node;
} tNode* LastNode(tList *list)//返回最后一个节点
{
tNode* node = (tNode*);
if (list->NodeCount != )
{
node = list->HeadNode.pre;
}
return node;
} tNode* tListPre(tList* list,tNode* node)//返回一个节点的前一个节点
{
if (node->pre == node)
{
return (tNode*);
}
else
{
return node->pre;
}
} tNode* tListNext(tList* list, tNode* node)//返回节点的后一个节点
{
if (node->next == node)
{
return (tNode*);
}
else
{
return node->next;
}
} void RemoveAll(tList* list)//删除所有节点
{
tNode* CurrentNode, *NextNode;
int count; NextNode = list->HeadNode.next;
for (count=list->NodeCount;count > ;count --)
{
CurrentNode = NextNode;
NextNode = CurrentNode->next; CurrentNode->pre = CurrentNode;
CurrentNode->next = CurrentNode;
} list->HeadNode.pre = &(list->HeadNode);
list->HeadNode.next = &(list->HeadNode); list->NodeCount = ;
} void tListHeadAdd(tList *list,tNode *node)//在头部添加节点
{
node->next = list->HeadNode.next;
node->pre = list->HeadNode.next->pre; list->HeadNode.next = node;
list->HeadNode.next->pre = node; list->NodeCount ++; } void tListLastAdd(tList *list,tNode *node)//在最后添加节点
{
node->pre = list->HeadNode.pre;
node->next = list->HeadNode.pre->next; list->HeadNode.pre->next = node;
list->HeadNode.pre = node; list->NodeCount ++;
} tNode* RemoveFirstNode(tList *list)//移除第一个节点
{
tNode *node = (tNode *);
if (list->HeadNode.next != )
{
node = list->HeadNode.next; node->next->pre = &(list->HeadNode);
list->HeadNode.next = node->next; list->NodeCount --; free(node);
}
else
{
return node;
}
} void tListInsertAfter(tList * list, tNode * nodeAfter, tNode * nodeToInsert)//在一个节点后添加一个节点
{
nodeToInsert->next = nodeAfter->next;
nodeToInsert->pre = nodeAfter; nodeAfter->next->pre = nodeToInsert;
nodeAfter->next = nodeToInsert; list->NodeCount ++;
} void tListRemove(tList * list, tNode * node)//移除节点
{
node->pre->next = node->next;
node->next->pre = node->pre; free(node); list->NodeCount --; }

在这个双向链表的实现过程中可以很好地实现队列操作,先进先出概念如这样验证:

int main()
{
tList list;
tNode *node;
int i = ; tListInit(&list); for (i = ; i < ; i++)
{
node = (tNode*)malloc(sizeof(tNode)); printf("Please input the number:");
scanf_s("%d",&node->data); tListLastAdd(&list, node);
} node = FirstNode(&list); printf("List is:");
for (i = ; i < ; i++)
{
printf("%d ",node->data);
node = node->next;
}
printf("\n");
getch();
return ;
}

实现效果为:

  在这个基础上还可以用于多种其他用处!

  PS:今天是自己第一天也是第一次写博客,在实现的过程中遇到很多问题也有很多想法,本来想一一记录但是发现写起来还是很艰辛,也许我现在就是一个小菜鸟,但是希望能够通过自己的努力一点一滴地积累逐渐成长,希望这个博客可以被我一直写下去!

                                          

                                                          写于广东海悟科技有限公司    2017-11-10    22:29:50

RTOS双向链表数据结构的更多相关文章

  1. Linux 内核里的数据结构:双向链表

    原文:https://blog.csdn.net/qq_33487044/article/details/78827260 双向链表 Linux 内核自己实现了双向链表,可以在 include/lin ...

  2. 常用数据结构-线性表及Java 动态数组 深究

    [Java心得总结六]Java容器中——Collection在前面自己总结的一篇博文中对Collection的框架结构做了整理,这里深究一下Java中list的实现方式 1.动态数组 In compu ...

  3. 浅谈java类集框架和数据结构(2)

    继续上一篇浅谈java类集框架和数据结构(1)的内容 上一篇博文简介了java类集框架几大常见集合框架,这一篇博文主要分析一些接口特性以及性能优化. 一:List接口 List是最常见的数据结构了,主 ...

  4. Java核心数据结构(List,Map,Set)原理与使用技巧

    JDK提供了一组主要的数据结构实现,如List.Map.Set等常用数据结构.这些数据都继承自 java.util.Collection 接口,并位于 java.util 包内. 1.List接口 最 ...

  5. 【转】Java学习---Java核心数据结构(List,Map,Set)使用技巧与优化

    [原文]https://www.toutiao.com/i6594587397101453827/ Java核心数据结构(List,Map,Set)使用技巧与优化 JDK提供了一组主要的数据结构实现, ...

  6. 双向链表-java完全解析

    原文:https://blog.csdn.net/nzfxx/article/details/51728516 "双向链表"-数据结构算法-之通俗易懂,完全解析 1.概念的引入 相 ...

  7. Java核心数据结构(List、Map、Set)原理与使用技巧

    JDK提供了一组主要的数据结构实现,如List.Set等常用数据结构.这些数据都继承自java.util.Collection接口,并位于java.util包内. 一.List接口 最重要的三种Lis ...

  8. 你真的懂Redis的5种基本数据结构吗?

    摘要: 你真的懂Redis的5种基本数据结构吗?这些知识点或许你还需要看看. 本文分享自华为云社区<你真的懂Redis的5种基本数据结构吗?这些知识点或许你还需要看看>,作者:李子捌. 一 ...

  9. [数据结构]链表相关的实现LinkList.cpp

    目录 LinkList.cpp //链表相关操作的实现 LinkList.h LinkListManager.cpp //链表相关实现函数的调用 LinkListManager.h LinkList. ...

随机推荐

  1. Spring编程式事务管理

    --------------------siwuxie095                                 Spring 编程式事务管理         以转账为例         ...

  2. C++ define与const

    C++中不但可以用define定义常量还可以用const定义常量,它们的区别如下: 用#define MAX 255定义的常量是没有类型的,所给出的是一个立即数,编译器只是把所定义的常量值与所定义的常 ...

  3. python之信号量【Semaphore】

    # 互斥锁同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据,比如 # 一个厕所有3个坑,那么最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去 import ...

  4. fiddler抓web请求

    原理 fiddler抓包原理 fiddler 调试器注册到操作系统因特网服务中,系统所有的网络请求都会走fiddler的代理,所以fiddler才能抓包. Debug traffic from any ...

  5. centos7下创建mysql5.6多实例

    一.mysql安装目录说明mysql5.6以二进制安装包安装在/data/mysql56下数据目录为/data/mysql56/data下配置文件为/etc/my.cnf下 二.多实例目录说明/mys ...

  6. HDOJ1242 Rescue(营救) 搜索

    Rescue Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Subm ...

  7. jQuery 用$.param(json) 将 Json 转换为 Url queryString

    如: var params = { param1: 'bar', param2: 'foo' }; var queryString = $.param(params); // queryString ...

  8. 原生JS 实现元素排序

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. part1:7-Linux网络配置

    1.虚拟机(Vmware)网络配置 VMware虚拟机对于不同的网络环境提供了三种网卡工作模式: Bridged:网桥模式: 在桥接模式下,计算机A充当路由器与虚拟机之间的“桥”,虚拟机通过计算机A的 ...

  10. =delete(c++11)

    1.为什么要阻止类对象的拷贝? 1)有些类,不需要拷贝和赋值运算符,如:IO类,以避免多个拷贝对象写入或读取相同的IO缓冲 2.如何阻止? 1)不定义拷贝构造函数和拷贝赋值运算符时,好心的编译器也会及 ...