Linux C 数据结构-双向链表(阴阳在六,何以言九~)

2023-11-22 02:10

本文主要是介绍Linux C 数据结构-双向链表(阴阳在六,何以言九~),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

0.  

 弄完了单链表,在看双向链表。怎么整?多写,多想,想不通画出来在想,再写,再模仿~

 

1.  没啥说的,敲代码~

 说点啥呢,注意自己的代码风格哦,要符合"潮流",不要独树一帜

 1.1 

 DList.h

#ifndef _DLIST_H_
#define _DLIST_H_typedef int data_t;/*节点指针*/
typedef struct node_t * PNode; /*表示返回的是地址*/
typedef PNode Position;/*定义节点类型*/
typedef struct node_t {data_t data;    // 数据域PNode  prev;    // 前驱指针PNode  next;    // 后继指针
}node_t;/*定义链表类型*/
typedef struct DList {PNode head;     // 指向头节点PNode tail;     // 指向尾节点int size;
}DList;/*分配值为i的节点 并返回节点地址*/
Position MakeNode(data_t i);/*释放p所指的节点*/
void FreeNode(PNode p);/*构建一个空的双向链表*/
DList * InitList();/*销毁一个双向链表*/
void DestroyList(DList * plist);/*将一个链表置为空 释放原链表节点空间*/
void ClearList(DList * plist);/*返回头节点地址*/
Position GetHead(DList * plist);/*返回尾节点地址*/
Position GetTail(DList * plist);/*返回链表大小*/
int GetSize(DList * plist);/*返回p的直接后继位置*/
Position GetNext(Position p);/*返回p的直接前驱位置*/
Position GetPrev(Position p);/*将pnode所指的节点插入第一个节点之前*/
PNode InsFirst(DList * plist, PNode pnode);/*将链表第一个节点删除并返回其地址*/
PNode DelFirst(DList * plist);/*返回节点的数据项*/
data_t GetData(Position p);/*设置节点的数据项*/
void SetData(Position p, data_t i);/*删除链表中的尾节点并返回其地址 改变链表的尾指针指向新的尾节点*/
PNode DelTail(DList * plist);/*在链表中p位置之前插入节点s*/
PNode InsBefore(DList * plist, Position p, PNode s);/*在链表中p位置之后插入节点s*/
PNode InsAfter(DList * plist, Position p, PNode s);/*返回在链表中第i个节点的位置*/
PNode LocatePos(DList * plist, int i);/*依次对链表中每个元素调用函数visit()*/
void ListTraverse(DList * plist, void (*visit)());#endif // _DLIST_H_

 DList.c

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>#include "DList.h"/*分配值为i的节点 并返回节点地址*/
Position 
MakeNode(data_t i)
{PNode p = NULL;p = (PNode)malloc(sizeof(node_t));  // 给节点分配内存if(p!=NULL) {p->data = i;p->prev = NULL;p->next = NULL;}return p;
}/*释放p所指的节点*/
void 
FreeNode(PNode p)
{free(p);
}/*构建一个空的双向链表*/
DList * 
InitList()
{DList *plist = (DList *)malloc(sizeof(DList));PNode head = MakeNode(0);if(plist!=NULL) {if(head!=NULL) {plist->head = head;plist->tail = head;plist->size = 0;} elsereturn NULL;}return plist;
}/*销毁一个双向链表*/
void 
DestroyList(DList * plist)
{ClearList(plist);free(GetHead(plist));free(plist);   
}/*判断链表是否为空表*/
int
IsEmpty(DList *plist)
{if(GetSize(plist)==0 && GetTail(plist)==GetHead(plist))return 1;elsereturn 0; 
}/*将一个链表置为空 释放原链表节点空间*/
void 
ClearList(DList * plist)
{PNode temp, p;p = GetTail(plist);while(!IsEmpty(plist)) {temp = GetPrev(p);FreeNode(p);p = temp;plist->tail = temp;plist->size--;}
}/*返回头节点地址*/
Position 
GetHead(DList * plist)
{return plist->head;
}/*返回尾节点地址*/
Position
GetTail(DList * plist)
{return plist->tail;
}/*返回链表大小*/
int 
GetSize(DList * plist)
{return plist->size;
}/*返回p的直接后继位置*/
Position 
GetNext(Position p)
{return p->next;
}/*返回p的直接前驱位置*/
Position 
GetPrev(Position p)
{return p->prev;
}/*将pnode所指的节点插入第一个节点之前*/
PNode 
InsFirst(DList * plist, PNode pnode)
{Position head = GetHead(plist);if(IsEmpty(plist))plist->tail = pnode;plist->size++;pnode->next = head->next;pnode->prev = head;if(head->next!=NULL) // head->next->prev = pnode;head->next = pnode;return pnode;
}/*将链表第一个节点删除并返回其地址*/
PNode 
DelFirst(DList * plist)
{Position head = GetHead(plist);Position p = head->next;if(p!=NULL) {if(p==GetTail(plist))plist->tail = p->prev;head->next = p->next;head->next->prev = head;plist->size--;}return p;
}/*返回节点的数据项*/
data_t 
GetData(Position p)
{return p->data;   
}/*设置节点的数据项*/
void 
SetData(Position p, data_t i)
{p->data = i;
}/*删除链表中的尾节点并返回其地址 改变链表的尾指针指向新的尾节点*/
PNode 
DelTail(DList * plist)
{Position p = NULL;if(IsEmpty(plist))return NULL;else {p = GetTail(plist);p->prev->next = p->next;plist->tail = p->prev;plist->size--;return p;}    
}/*在链表中p位置之前插入节点s*/
PNode 
InsBefore(DList * plist, Position p, PNode s)
{s->prev = p->prev;s->next = p;p->prev->next = s;p->prev = s;plist->size++;return s;
}/*在链表中p位置之后插入节点s*/
PNode 
InsAfter(DList * plist, Position p, PNode s)
{s->next = p->next;s->prev = p;if(p->next!=NULL)p->next->prev = s;p->next = s;if(p == (GetTail(plist)))plist->tail = s;plist->size++;return s;
}/*返回在链表中第i个节点的位置*/
PNode 
LocatePos(DList * plist, int i)
{int cnt = 0;Position p = GetHead(plist);if(i>GetSize(plist) || i<1)return 0;while(++cnt<=i)p = p->next;return p;
}/*依次对链表中每个元素调用函数visit()*/
void 
ListTraverse(DList * plist, void (*visit)())
{Position p = GetHead(plist);if(IsEmpty(plist))exit(0);else {while(p->next!=NULL) {p = p->next;visit(p->data);}}}

 test.c

#include <stdio.h>
#include "Dlist.h"void 
print(data_t i)
{printf("数据项为 %d\n", i);
}int main(int argc, char * argv[])
{DList * plist = NULL;PNode p = NULL;plist = InitList();p = InsFirst(plist, MakeNode(1));InsBefore(plist, p, MakeNode(2));InsAfter(plist, p, MakeNode(3));InsAfter(plist, p, MakeNode(11));printf("p前驱位置的值为 %d\n", GetData(GetPrev(p)));printf("p位置的值为 %d\n", GetData(p));printf("p后继位置的值为 %d\n", GetData(GetNext(p)));printf("遍历输出各节点数据项:\n");ListTraverse(plist, print);printf("除了头节点该链表共有 %d 个节点\n", GetSize(plist));FreeNode(DelFirst(plist));printf("删除了头节点该链表共有 %d 个节点\n", GetSize(plist));printf("删除第一个节点后重新遍历输出为:\n");ListTraverse(plist, print);printf("删除了第一个节点后该链表共有 %d 个节点\n", GetSize(plist));printf("销毁链表...\n");DestroyList(plist);return 0;
}

 Demo1:Makefile 文件

CC = gcc
CFLAGS = -g -Wall -o2RUNE = $(CC) $(CFLAGS) $(object) -o $(exe)
RUNO = $(CC) $(CFLAGS) -c $< -o $@ .RHONY:cleanobject = test.o Dlist.o
exe = Dlist$(exe):$(object)$(RUNE)%.o:%.c Dlist.h$(RUNO)
%.o:%.c$(RUNO)clean:-rm -rf *.o Dlist *~~

 运行

 

1.2  

 double_link.h 

#ifndef _DOUBLE_LINK_H_
#define _DOUBLE_LINK_H_// 节点类型
typedef struct node_t {struct node_t * prev;struct node_t * next;void * data;
}node_t;// 新建 双向循环链表.成功,返回0;否则,返回-1
extern int create_dlink();// 销毁 双向循环链表.成功,返回0;否则,返回-1
extern int destroy_dlink();// 双向链表是否为空.为空的话返回1;否则,返回0
extern int dlink_is_empty();// 返回 双向链表的大小
extern int dlink_size();// 获取 双向链表中第index位置的元素.成功,返回节点指针;否则,返回NULL
extern void * dlink_get(int index);// 获取 双向链表中第1个元素.成功,返回节点指针;否则,返回NULL
extern void * dlink_get_first();// 获取 双向链表中最后1个元素.成功,返回节点指针;否则,返回NULL
extern void * dlink_get_last();// 将value插入到index位置.成功,返回0;否则,返回-1
extern int dlink_insert(int index, void * pval);// 将value插入到表头位置.成功,返回0;否则,返回-1
extern int dlink_insert_first(void * pval);// 将value插入到末尾位置.成功,返回0;否则,返回-1
extern int dlink_append_last(void * pval);// 删除 双向链表中index位置的节点.成功,返回0;否则,返回-1
extern int dlink_delete(int index);// 删除 第一个节点.成功,返回0;否则,返回-1
extern int dlink_delete_first();// 删除 最后一个节点.成功,返回0;否则,返回-1
extern int dlink_delete_last();#endif //_DOUBLE_LINK_H_

 double_link.c

/********************* 双向循环链表实现*******************/
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>#include "double_link.h"// 表头,不存放元素值
static node_t * phead = NULL;// 节点个数
static int count = 0;// 创建节点
static node_t * 
create_node(void * pval)
{node_t * pnode = NULL;pnode = (node_t *)malloc(sizeof(node_t));if(NULL == pnode) return NULL;// 默认pnode的前一个节点和后一节点都指向它自身// 双向循环链表,这里不能将pnode->prev = NULL;pnode->next = NULL;pnode->prev = pnode->next = pnode;pnode->data = pval;return pnode;
}// 新建 双向循环链表。成功,返回0;否则,返回-1
int 
create_dlink()
{// 创建头phead = create_node(NULL); // 头节点数据域为NULLif(!phead)return -1;// 节点个数为0count = 0;return 0;
}// 双向链表是否为空 。为空的话返回1;否则,返回0。
int 
dlink_is_empty()
{if(count == 0)return 1;return 0;
}// 返回 双向链表的大小
int dlink_size()
{return count;
}// 获取 双向链表中第 index 位置的节点
static 
node_t * get_node(int index)
{if(index < 0 || index >= count)return NULL;// 正向查找if(index <= (count/2)) {int i = 0;node_t * pnode = phead->next;while((i++)<index)pnode = pnode->next;return pnode;}// 反向查找int j = 0;int rindex = count - index -1;node_t * rnode = phead->prev;while((j++) < rindex)rnode = rnode->prev;return rnode;
}// 获取 双向链表中第index位置的元素。成功,返回节点指针;否则,返回NULL。
void * dlink_get(int index)
{node_t * pindex = get_node(index);if(!pindex)return NULL;return pindex->data;
}// 获取 双向链表中第1个元素 。成功,返回节点指针;否则,返回NULL。
void * dlink_get_first()
{return dlink_get(0);
}// 获取“双向链表中最后1个元素”。成功,返回节点指针;否则,返回NULL。
void * 
dlink_get_last()
{return dlink_get(count-1);
}// 将“value”插入到index位置。成功,返回0;否则,返回-1。
int 
dlink_insert(int index, void * pval)
{// 插入表头if(index == 0)return dlink_insert_first(pval);// 获取插入的位置对应的节点node_t * pindex = get_node(index);if(!pindex)return -1;// 创建 节点node_t * pnode = create_node(pval);if(!pnode)return -1;pnode->prev = pindex->prev;pnode->next = pindex;pindex->prev->next = pnode; // pindex 前一个节点的后继指针指向新节点pindex->prev = pnode;count++;return 0;
}// 将value 插入到表头位置。成功,返回0;否则,返回-1。
int 
dlink_insert_first(void * pval)
{node_t * pnode = create_node(pval);if(!pnode)return -1;pnode->prev = phead;pnode->next = phead->next;phead->next->prev = pnode;phead->next = pnode;count++;return 0;
}// 将value 插入到末尾位置。成功,返回0;否则,返回-1。
int 
dlink_append_last(void * pval)
{node_t * pnode = create_node(pval);if(!pnode)return -1;pnode->prev= phead->prev;pnode->next = phead;phead->prev->next = pnode;phead->prev = pnode;count++;return 0;
}// 删除 双向链表中index位置的节点 。成功,返回0;否则,返回-1
int 
dlink_delete(int index)
{node_t * pindex = get_node(index);if(!pindex)return -1;pindex->next->prev = pindex->prev;pindex->prev->next = pindex->next;free(pindex);count--;return 0;
}// 删除第一个节点。成功,返回0;否则,返回-1
int 
dlink_delete_first()
{return dlink_delete(0);
}// 删除 最后一个节点。成功,返回0;否则,返回-1
int
dlink_delete_last()
{return dlink_delete(count-1);
}// 撤销 双向链表 。成功,返回0;否则,返回-1
int 
destroy_dlink()
{if(!phead)return -1;node_t * pnode = phead->next;node_t * ptmp = NULL;//遍历节点while(pnode!=phead) {ptmp = pnode;pnode = pnode->next;free(ptmp);}free(phead);phead = NULL;count = 0;return 0;
}

Makefile 套路走起,(代码临摹别人的,makefile要原创的哦,上下长得一样,俗称 套路)

CC = gcc
CFLAGS = -g -Wall -o2RUNE = $(CC) $(CFLAGS) $(object) -o $(exe)
RUNO = $(CC) $(CFLAGS) -c $< -o $@ .RHONY:cleanobject = test.o double_link.o
exe = DlinkLoop$(exe):$(object)$(RUNE)%.o:%.c double_link.h$(RUNO)
%.o:%.c$(RUNO)clean:-rm -rf *.o DlinkLoop *~~

execute

 

2. 鸣谢

惯例,感谢二位少侠,Cheers!!!
https://blog.csdn.net/zqixiao_09/article/details/50145661
http://www.cnblogs.com/skywang12345/p/3561803.html

 

3. 后记

九阴真经 - 总纲-2

 

五脏六腑之精气,皆上注于目而为之精。精之案为眼,骨之精为瞳子,筋之精为络,其案气之精为白眼,

肌肉之为精为约束,裹撷筋骨血气之精而与脉并为系,上属于脑,后出于项中。故邪中与项,因逢其身

之虚,其人深,则随眼系以入于脑,入手面腼则脑转,脑转则引目系急,目系急则目眩以转矣。邪其精

,其精所中不相比亦则精散,精散则视歧,视歧见两物。

阴阳在六,何以言九。太极生两仪,天地初刨判。六阴已机,逢七归元太素,太素西方金德,阴之清纯

,寒值渊源。

 

内功心法

第一重诀曰:子午卯酉四正时,归气丹田掌前推。面北背南朝天盘,意随两掌行当中。意注丹田一阳动,

左右回收对两穴。拜佛合什当胸作,真气旋转贯其中。气行任督小周天,温养丹田一柱香。快慢合乎三

十六,九阴神功第一重。

注解:每日子、午、卯、酉四正时,找一阴气重的地方,最好为四高中低。面北而坐,五心朝天,静心

绝虑,意守丹田,到一阳初动之时,双手在胸前合什,指尖朝前。引丹田之气沿督脉上行,任脉下归丹

田。如此待小周天三十六圈。由慢至快。气归丹田后,双掌前推,掌心向前,掌指朝天,气行两掌。双

掌指下垂,掌指朝下,掌心朝下,迅速收回,左手掌心对准气海穴,右手掌心对准命门穴,真气随手式

成螺旋状贯入气海、命门两穴。汇于丹田内。如此意守下丹田一柱香的时间。待此功练有一定功力,能

收发自如,有抗寒之功时可修第二重。

转载于:https://www.cnblogs.com/zhaoosheLBJ/p/9369128.html

这篇关于Linux C 数据结构-双向链表(阴阳在六,何以言九~)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/406730

相关文章

Linux换行符的使用方法详解

《Linux换行符的使用方法详解》本文介绍了Linux中常用的换行符LF及其在文件中的表示,展示了如何使用sed命令替换换行符,并列举了与换行符处理相关的Linux命令,通过代码讲解的非常详细,需要的... 目录简介检测文件中的换行符使用 cat -A 查看换行符使用 od -c 检查字符换行符格式转换将

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

Linux系统中卸载与安装JDK的详细教程

《Linux系统中卸载与安装JDK的详细教程》本文详细介绍了如何在Linux系统中通过Xshell和Xftp工具连接与传输文件,然后进行JDK的安装与卸载,安装步骤包括连接Linux、传输JDK安装包... 目录1、卸载1.1 linux删除自带的JDK1.2 Linux上卸载自己安装的JDK2、安装2.1

C#数据结构之字符串(string)详解

《C#数据结构之字符串(string)详解》:本文主要介绍C#数据结构之字符串(string),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录转义字符序列字符串的创建字符串的声明null字符串与空字符串重复单字符字符串的构造字符串的属性和常用方法属性常用方法总结摘

Linux卸载自带jdk并安装新jdk版本的图文教程

《Linux卸载自带jdk并安装新jdk版本的图文教程》在Linux系统中,有时需要卸载预装的OpenJDK并安装特定版本的JDK,例如JDK1.8,所以本文给大家详细介绍了Linux卸载自带jdk并... 目录Ⅰ、卸载自带jdkⅡ、安装新版jdkⅠ、卸载自带jdk1、输入命令查看旧jdkrpm -qa

Linux samba共享慢的原因及解决方案

《Linuxsamba共享慢的原因及解决方案》:本文主要介绍Linuxsamba共享慢的原因及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux samba共享慢原因及解决问题表现原因解决办法总结Linandroidux samba共享慢原因及解决

新特性抢先看! Ubuntu 25.04 Beta 发布:Linux 6.14 内核

《新特性抢先看!Ubuntu25.04Beta发布:Linux6.14内核》Canonical公司近日发布了Ubuntu25.04Beta版,这一版本被赋予了一个活泼的代号——“Plu... Canonical 昨日(3 月 27 日)放出了 Beta 版 Ubuntu 25.04 系统镜像,代号“Pluc

Linux安装MySQL的教程

《Linux安装MySQL的教程》:本文主要介绍Linux安装MySQL的教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux安装mysql1.Mysql官网2.我的存放路径3.解压mysql文件到当前目录4.重命名一下5.创建mysql用户组和用户并修

Linux上设置Ollama服务配置(常用环境变量)

《Linux上设置Ollama服务配置(常用环境变量)》本文主要介绍了Linux上设置Ollama服务配置(常用环境变量),Ollama提供了多种环境变量供配置,如调试模式、模型目录等,下面就来介绍一... 目录在 linux 上设置环境变量配置 OllamPOgxSRJfa手动安装安装特定版本查看日志在

Linux系统之主机网络配置方式

《Linux系统之主机网络配置方式》:本文主要介绍Linux系统之主机网络配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、查看主机的网络参数1、查看主机名2、查看IP地址3、查看网关4、查看DNS二、配置网卡1、修改网卡配置文件2、nmcli工具【通用