首先编写头文件,头文件里做相关的定义和声明,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语言一个双向链表的实现的更多相关文章

  1. C++语言实现双向链表

    这篇文章是关于利用C++模板的方式实现的双向链表以及双向链表的基本操作,在之前的博文C语言实现双向链表中,已经给大家分析了双向链表的结构,并以图示的方式给大家解释了双向链表的基本操作.本篇文章利用C+ ...

  2. C语言实现双向链表

    目前我们所学到的链表,无论是动态链表还是静态链表,表中各节点中都只包含一个指针(游标),且都统一指向直接后继节点,通常称这类链表为单向链表(或单链表). 虽然使用单链表能 100% 解决逻辑关系为 & ...

  3. 用C语言把双向链表中的两个结点交换位置,考虑各种边界问题。

    用C语言把双向链表中的两个结点交换位置,考虑各种边界问题. [参考] http://blog.csdn.net/silangquan/article/details/18051675

  4. Java实现一个双向链表的倒置功能

    题目要求:Java实现一个双向链表的倒置功能(1->2->3 变成 3->2->1) 提交:代码.测试用例,希望可以写成一个Java小项目,可以看到单元测试部分 该题目的代码, ...

  5. 跟踪LinkedList源码,通过分析双向链表实现原理,自定义一个双向链表

    1.LinkedList实现的基本原理 LinkedList是一个双向链表,它主要有两个表示头尾节点的成员变量first  .last,因其有头尾两个节点,所以从头或从尾操作数据都非常容易快捷.Lin ...

  6. C语言实现双向链表删除节点、插入节点、双向输出等操作

    #include<cstdio> #include<cstdlib> typedef struct DoubleLinkedList { int data; struct Do ...

  7. C语言数据结构----双向链表

    概括:主要说明双向链表的基本概念和具体操作以及源代码. 一.基本概念 1.有了单链表以后我们可以把内存中小块的空间联系在一起,并且把每一个小块都存储上我们想要存储的数值.但是单链表只有一个next,我 ...

  8. 大二作业——操作系统实验——C语言用双向链表,模拟实现动态分区式存储管理

    实验:动态分区式存储管理 实验内容: 编写程序模拟完成动态分区存储管理方式的内存分配和回收.实验具体包括:首先确定内存空闲分配表:然后采用最佳适应算法完成内存空间的分配和回收:最后编写主函数对所做工作 ...

  9. C语言-一个fopen函数中未使用二进制模式(b)引发的血案

    转自:http://blog.csdn.net/hinyunsin/article/details/6401854 最近写了一个网络文件传输模块,为了让这个模块具有更好的移植性,我尽量使用C标准IO ...

随机推荐

  1. NOIP2015-D2T3运输计划

    题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球. 小 P 掌管一家 ...

  2. hdu 5014(贪+位运算)

    题意:给你n+1个数(0->n),让你为这n+1个数在0->n中分别找一个数与其异或,求最后的最大值 思路:假设一个数5 (二进制1 0 1),则找的另一个数在5的0位上最好是1 , 1位 ...

  3. poj2449 (第k条最短路)

    题意:求n个点中,a到b的第k条最短路 思路: 用最短路求出估价函数的h,再在搜索过程中记录g,利用A*求出 最开始想到的便是A*和最短路,但是脑子抽了,居然一个一个去求- -,TL了后才发现可以倒着 ...

  4. qemu 模拟-arm-mini2440开发板-启动u-boot,kernel和nfs文件系统【转】

    转自:http://www.cnblogs.com/riskyer/p/3366001.html qemu 本文介绍了如何编译u-boot.linux kernel,然后用qemu启动u-boot和l ...

  5. 用 ConfigMap 管理配置 - 每天5分钟玩转 Docker 容器技术(159)

    Secret 可以为 Pod 提供密码.Token.私钥等敏感数据:对于一些非敏感数据,比如应用的配置信息,则可以用 ConfigMap. ConfigMap 的创建和使用方式与 Secret 非常类 ...

  6. Linux(centos7)下安装Docker

    近期公司开始推Docker技术.这个系列的文章都是基于CentOS7系统下进行讲解的. Docker简介 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器 ...

  7. Printer for Me

    今天,良心系部终于给我配了打印机^^. 办公室门外还挂了牌子.

  8. spring web项目下,判断项目是否启动完成

    本文同时发布于见鬼网:https://faceghost.com/article/483341 概述:spring 加载完成后,我们有时候会做一些初始化工作,如加载一些缓存,DB,等,这里采用实现Se ...

  9. 浏览器本地下拉框查询选择js

    首先需要引用jquery-1.7.2.js. 页面下拉框有对应的数据,此下拉框的查询将不与服务器交互.本地下拉框查询.暂不支持通过键盘上下按键和enter键控制 // JavaScript Docum ...

  10. Errors running builder 'DeploymentBuilder' on project '工程名'

    打开myEclipse就会报 Errors running builder 'DeploymentBuilder' on project '工程名' xxxNullpointException 的错误 ...