C语言一个双向链表的实现
首先编写头文件,头文件里做相关的定义和声明,DList.h内容如下:
- #ifndef DList_H
- #define DList_H
- typedef int Item;
- typedef struct Node * PNode;
- typedef PNode Position;
- /*定义节点类型*/
- typedef struct Node
- {
- Item data; /*数据域*/
- PNode previous; /*指向前驱*/
- PNode next; /*指向后继*/
- }Node;
- /*定义链表类型*/
- typedef struct
- {
- PNode head; /*指向头节点*/
- PNode tail; /*指向尾节点*/
- int size;
- }DList;
- /*分配值为i的节点,并返回节点地址*/
- Position MakeNode(Item 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 GetPrevious(Position p);
- /*将pnode所指节点插入第一个节点之前*/
- PNode InsFirst(DList *plist,PNode pnode);
- /*将链表第一个节点删除并返回其地址*/
- PNode DelFirst(DList *plist);
- /*获得节点的数据项*/
- Item GetItem(Position p);
- /*设置节点的数据项*/
- void SetItem(Position p,Item i);
- /*删除链表中的尾节点并返回其地址,改变链表的尾指针指向新的尾节点*/
- PNode Remove(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.c内容如下:
- #include"DList.h"
- #include<malloc.h>
- #include<stdlib.h>
- /*分配值为i的节点,并返回节点地址*/
- Position MakeNode(Item i)
- {
- PNode p = NULL;
- p = (PNode)malloc(sizeof(Node));
- if(p!=NULL)
- {
- p->data = i;
- p->previous = 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;
- }
- else
- return 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;
- else
- return 0;
- }
- /*将一个链表置为空表,释放原链表节点空间*/
- void ClearList(DList *plist)
- {
- PNode temp,p;
- p = GetTail(plist);
- while(!IsEmpty(plist))
- {
- temp = GetPrevious(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 GetPrevious(Position p)
- {
- return p->previous;
- }
- /*将pnode所指节点插入第一个节点之前*/
- PNode InsFirst(DList *plist,PNode pnode)
- {
- Position head = GetHead(plist);
- if(IsEmpty(plist))
- plist->tail = pnode;
- plist->size++;
- pnode->next = head->next;
- pnode->previous = head;
- if(head->next!=NULL)
- head->next->previous = 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->previous;
- head->next = p->next;
- head->next->previous = head;
- plist->size--;
- }
- return p;
- }
- /*获得节点的数据项*/
- Item GetItem(Position p)
- {
- return p->data;
- }
- /*设置节点的数据项*/
- void SetItem(Position p,Item i)
- {
- p->data = i;
- }
- /*删除链表中的尾节点并返回地址,改变链表的尾指针指向新的尾节点*/
- PNode Remove(DList *plist)
- {
- Position p=NULL;
- if(IsEmpty(plist))
- return NULL;
- else
- {
- p = GetTail(plist);
- p->previous->next = p->next;
- plist->tail = p->previous;
- plist->size--;
- return p;
- }
- }
- /*在链表中p位置之前插入新节点s*/
- PNode InsBefore(DList *plist,Position p,PNode s)
- {
- s->previous = p->previous;
- s->next = p;
- p->previous->next = s;
- p->previous = s;
- plist->size++;
- return s;
- }
- /*在链表中p位置之后插入新节点s*/
- PNode InsAfter(DList *plist,Position p,PNode s)
- {
- s->next = p->next;
- s->previous = p;
- if(p->next != NULL)
- p->next->previous = 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 NULL;
- 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"DList.h"
- #include<stdio.h>
- void print(Item i)
- {
- printf("数据项为%d n",i);
- }
- main()
- {
- DList *plist = NULL;
- PNode p = NULL;
- plist = InitList();
- p = InsFirst(plist,MakeNode(1));
- InsBefore(plist,p,MakeNode(2));
- InsAfter(plist,p,MakeNode(3));
- printf("p前驱位置的值为%dn",GetItem(GetPrevious(p)));
- printf("p位置的值为%dn",GetItem(p));
- printf("p后继位置的值为%dn",GetItem(GetNext(p)));
- printf("遍历输出各节点数据项:n");
- ListTraverse(plist,print);
- printf("除了头节点该链表共有%d个节点n",GetSize(plist));
- FreeNode(DelFirst(plist));
- printf("删除第一个节点后重新遍历输出为:n");
- ListTraverse(plist,print);
- printf("除了头节点该链表共有%d个节点n",GetSize(plist));
- DestroyList(plist);
- printf("链表已被销毁n");
- }
C语言一个双向链表的实现的更多相关文章
- C++语言实现双向链表
这篇文章是关于利用C++模板的方式实现的双向链表以及双向链表的基本操作,在之前的博文C语言实现双向链表中,已经给大家分析了双向链表的结构,并以图示的方式给大家解释了双向链表的基本操作.本篇文章利用C+ ...
- C语言实现双向链表
目前我们所学到的链表,无论是动态链表还是静态链表,表中各节点中都只包含一个指针(游标),且都统一指向直接后继节点,通常称这类链表为单向链表(或单链表). 虽然使用单链表能 100% 解决逻辑关系为 & ...
- 用C语言把双向链表中的两个结点交换位置,考虑各种边界问题。
用C语言把双向链表中的两个结点交换位置,考虑各种边界问题. [参考] http://blog.csdn.net/silangquan/article/details/18051675
- Java实现一个双向链表的倒置功能
题目要求:Java实现一个双向链表的倒置功能(1->2->3 变成 3->2->1) 提交:代码.测试用例,希望可以写成一个Java小项目,可以看到单元测试部分 该题目的代码, ...
- 跟踪LinkedList源码,通过分析双向链表实现原理,自定义一个双向链表
1.LinkedList实现的基本原理 LinkedList是一个双向链表,它主要有两个表示头尾节点的成员变量first .last,因其有头尾两个节点,所以从头或从尾操作数据都非常容易快捷.Lin ...
- C语言实现双向链表删除节点、插入节点、双向输出等操作
#include<cstdio> #include<cstdlib> typedef struct DoubleLinkedList { int data; struct Do ...
- C语言数据结构----双向链表
概括:主要说明双向链表的基本概念和具体操作以及源代码. 一.基本概念 1.有了单链表以后我们可以把内存中小块的空间联系在一起,并且把每一个小块都存储上我们想要存储的数值.但是单链表只有一个next,我 ...
- 大二作业——操作系统实验——C语言用双向链表,模拟实现动态分区式存储管理
实验:动态分区式存储管理 实验内容: 编写程序模拟完成动态分区存储管理方式的内存分配和回收.实验具体包括:首先确定内存空闲分配表:然后采用最佳适应算法完成内存空间的分配和回收:最后编写主函数对所做工作 ...
- C语言-一个fopen函数中未使用二进制模式(b)引发的血案
转自:http://blog.csdn.net/hinyunsin/article/details/6401854 最近写了一个网络文件传输模块,为了让这个模块具有更好的移植性,我尽量使用C标准IO ...
随机推荐
- 洛谷P2388 阶乘之乘
题目背景 不告诉你-- 题目描述 求出1!*2!*3!*4!*--*n!的末尾有几个零 输入输出格式 输入格式: n(n<=10^8) 输出格式: 有几个零 输入输出样例 输入样例#1: 复制 ...
- POJ1509 Glass Beads
Glass Beads Time Limit: 3000MS Memory Limit: 10000K Total Submissions: 4314 Accepted: 2448 Descr ...
- [BZOJ]3527 力(ZJOI2014)
第一次背出FFT模板,在此mark一道裸题. Description 给出n个数qi,给出Fj的定义如下: 令Ei=Fi/qi,求Ei. Input 第一行一个整数n. 接下来n行每行输入一个数,第i ...
- ubuntu 安装 WPS for Linux(ubuntu)字体配置(字体缺失解决办法)及卸载libreoffice
从官网下载安装wps for Linux sudo dpkg -i wps-office_10.1.0.5672~a21_amd64.deb 启动WPS for Linux后,出现提示"系统 ...
- RHEL 7修改ssh默认端口号
RHEL7修改默认端口号(默认port22)初次安装系统完毕后默认情况下系统已经启动了sshd服务当然我们也可以先进行检查: 步骤1,检查是否已安装ssh服务 步骤2,检查服务是否已开启 如上图所示显 ...
- vscode 搭建go开发环境的13个插件的安装
由于网的问题 大家都不能直接go get 这里从易到难按难度给大家推荐几种方法 最简单的FQ 但是能FQ你还不能装 请问是假的FQ吗? 第一 用git 直接git反而能从那边趴下代码 但是要自己go ...
- Algorithm in Practice - Sorting and Searching
Algorithm in Practice Author: Zhong-Liang Xiang Date: Aug. 1st, 2017 不完整, 部分排序和查询算法, 需添加. Prerequisi ...
- 如何搭建lamp(CentOS7+Apache+MySQL+PHP)环境
我的环境:虚拟机是:VMware-workstation-full-8.0.0-471780.exe:Linux系统用的是:CentOS-7-x86_64-Minimal-1503-01.ios;(阿 ...
- 六星经典CSAPP-笔记(11)网络编程
六星经典CSAPP-笔记(11)网络编程 参照<深入理解计算机系统>简单学习了下Unix/Linux的网络编程基础知识,进一步深入学习Linux网络编程和TCP/IP协议还得参考Steve ...
- 初识Spark2.0之Spark SQL
内存计算平台spark在今年6月份的时候正式发布了spark2.0,相比上一版本的spark1.6版本,在内存优化,数据组织,流计算等方面都做出了较大的改变,同时更加注重基于DataFrame数据组织 ...