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 ...
随机推荐
- hdu 5885 FFT
XM Reserves Time Limit: 10000/10000 MS (Java/Others) Memory Limit: 102400/102400 K (Java/Others)T ...
- UVA 1481 Genome Evolution
Xi, a developmental biologist is working on developmental distances of chromosomes. A chromosome, in ...
- Python【第一课】 Python简介和基础
本节内容 Python安装(windows) 第一个程序(windows中的python) 变量 字符编码 注释 用户输入 模块初步认识 数据类型 数据运算 表达式if...else 表达式for l ...
- 选项卡js版封装
以下是封装函数: // id:最外边大盒的id名function tab(id,ev){ var oWrap = document.getElementById(id); ...
- TCP/UDP的区别
TCP与UDP区别 TCP提供的是面向连接的.可靠的数据流传输: UDP提供的是非面向连接的.不可靠的数据流传输. TCP提供可靠的服务,通过TCP连接传送的数据,无差错.不丢失,不重复,按序到达:U ...
- Servlet-----response.getWriter().write()与out.print()的区别
50313 1.首先介绍write()和print()方法的区别: (1).write():仅支持输出字符类型数据,字符.字符数组.字符串等 (2).print():可以将各种类型(包括Obje ...
- Java transient关键字使用小结
1.transient关键字只能修饰变量,而不能修饰方法和类.注意,本地变量是不能被transient关键字修饰的.2.被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被t ...
- 判断是否是IE9浏览器的最短语句 var ie=!-[1,]
没错,上面这个语句就可以判断浏览器是不是IE9以下的.why?1.[1,]在现代浏览器(ie包括ie9及以上)会被转换成[1], 而ie9以下就会转换成[1,undefined].2.分别对[1],和 ...
- C#系统之垃圾回收
1. using System; using System.Collections.Generic; using System.Linq; using System.Text; using Syste ...
- Linux 虚存的性能问题
虚存子系统是所有 UNIX 系统的核心组件.下面讨论虚存系统的实现及其对操作系统中几乎其他所有子系统的作用和影响.首先详细说明一些基本的内存管理问题:然后具体分析 Linux 操作系统如何实施虚存管理 ...