双向链表的功能实现

/* P.10 的预定义常量和类型 */
#define TRUE        1
#define FALSE        0
#define OK        1
#define ERROR        0
#define INFEASIBLE    -1
#define OVERFLOW    -2

typedef int Status;

/* P.28 形式定义 */
typedef int ElemType;    //可根据需要修改元素的类型

typedef struct DuLNode {
    ElemType        data;    //存放数据
    struct DuLNode *prior;    //存放直接前驱的指针
    struct DuLNode *next;    //存放直接后继的指针
} DuLNode, *DuLinkList;

/* P.19-20的抽象数据类型定义转换为实际的C语言 */
Status    InitList(DuLinkList *L);
Status    DestroyList(DuLinkList *L);
Status    ClearList(DuLinkList *L);
Status    ListEmpty(DuLinkList L);
int    ListLength(DuLinkList L);
Status    GetElem(DuLinkList L, int i, ElemType *e);
int    LocateElem(DuLinkList L, ElemType e, Status (*compare)(ElemType e1, ElemType e2));
Status    PriorElem(DuLinkList L, ElemType cur_e, ElemType *pre_e);
Status    NextElem(DuLinkList L, ElemType cur_e, ElemType *next_e);
Status    ListInsert(DuLinkList *L, int i, ElemType e);
Status    ListDelete(DuLinkList *L, int i, ElemType *e);

Status    ListTraverse(DuLinkList L, Status (*visit)(ElemType e));

#include <stdio.h>
#include <stdlib.h>        //malloc/realloc函数
#include <unistd.h>        //exit函数
#include "linear_list_DL.h"    //形式定义
#include <stdio.h>
#include <stdlib.h>        //malloc/realloc函数
#include <unistd.h>        //exit函数
#include "linear_list_DL.h"    //形式定义

/* 初始化线性表 */
Status InitList(DuLinkList *L)
{
    /* 申请头结点空间,赋值给头指针 */
    *L = (DuLNode *)malloc(sizeof(DuLNode));
    if (*L==NULL)
    exit(OVERFLOW);

    (*L)->prior = NULL;
    (*L)->next  = NULL;
    return OK;
}

/* 删除线性表 */
Status DestroyList(DuLinkList *L)
{
    DuLinkList q, p = *L; //指向首元

    /* 整个链表(含头结点)依次释放(同单链表,不考虑prior指针,只用next) */
    while(p != (*L)) {    //若链表为空,则循环不执行
    q=p->next; //抓住链表的下一个结点
    free(p);
    p=q;
    }

    *L=NULL;    //头指针置NULL
    return OK;
}

/* 清除线性表(保留头结点) */
Status ClearList(DuLinkList *L)
{
    DuLinkList q, p = (*L)->next;

    /* 从首元结点开始依次释放(同单链表,不考虑prior指针,只用next) */
    while(p != (*L)) {
    q = p->next;   //抓住链表的下一个结点
    free(p);
    p = q;
    }

    (*L)->next = NULL; //头结点的prior域置NULL
    (*L)->next = NULL; //头结点的next域置NULL
    return OK;
}

/* 判断是否为空表 */
Status ListEmpty(DuLinkList L)
{
    /* 判断头结点的next域即可(同单链表) */
    if (L->next==NULL)
    return TRUE;
    else
    return FALSE;
}

/* 求表的长度 */
int ListLength(DuLinkList L)
{
    DuLinkList p = L->next; //指向首元结点
    int len=0;

    /* 循环整个链表,进行计数(同单链表) */
    while(p) {
    p = p->next;
    len++;
    }

    return len;
}

/* 取表中元素 */
Status GetElem(DuLinkList L, int i, ElemType *e)
{
    DuLinkList p = L->next;    //指向首元结点
    int    pos = 1;        //初始位置为1
 
    /* 链表不为NULL 且 未到第i个元素(同单链表) */
    while(p!=NULL && pos<i) {
        p=p->next;
        pos++;
    }

    if (!p || pos>i)
        return ERROR;

    *e = p->data;
    return OK;
}

/* 查找符合指定条件的元素 */
int LocateElem(DuLinkList L, ElemType e, Status (*compare)(ElemType e1, ElemType e2))
{
    DuLinkList p = L->next;    //首元结点
    int    pos = 1;        //初始位置

    /* 循环整个链表(同单链表)  */
    while(p && (*compare)(e, p->data)==FALSE) {
    p=p->next;
    pos++;
    }

    return p ? pos:0;
}

/* 查找符合指定条件的元素的前驱元素 */
Status PriorElem(DuLinkList L, ElemType cur_e, ElemType *pre_e)
{
    DuLinkList p = L->next;    //指向首元结点

    if (p==NULL)    //空表直接返回
        return ERROR;

    /* 从第2个结点开始循环整个链表(如果比较相等,保证有前驱)(同单链表) */
    while(p->next && p->next->data != cur_e)
        p = p->next;

    if (p->next==NULL) //未找到
        return ERROR;
 
    *pre_e = p->data;
    return OK;
}

/* 查找符合指定条件的元素的后继元素 */
Status NextElem(DuLinkList L, ElemType cur_e, ElemType *next_e)
{
    DuLinkList p = L->next;  //首元结点

    if (p==NULL)    //空表直接返回
        return ERROR;    

    /* 有后继结点且当前结点值不等时继续(同单链表) */
    while(p->next && p->data!=cur_e)
        p = p->next;

    if (p->next==NULL)
        return ERROR;

    *next_e = p->next->data;
    return OK;
}

/* 在指定位置前插入一个新元素 */
Status ListInsert(DuLinkList *L, int i, ElemType e)
{
#if 0
    DuLinkList s, p = *L;    //p指向头结点
    int      pos  = 1;

    /* 寻找第i个结点(i可能是表长+1) */
    while(p->next && pos<i-1) {
    p=p->next;
    pos++;
    }

    if (p->next==NULL || pos>i-1)  //i值非法则返回
    return ERROR;

    //执行到此表示找到指定位置,p指向第i-1个结点

    s = (DuLinkList)malloc(sizeof(DuLNode));
    if (s==NULL)
    return OVERFLOW;

    if (pos==i-1) {
    }
    else {
    /* 注意,p可能是NULL */
    s->data = e;     //新结点数据域赋值
    s->prior = p->prior;
    p->prior->next = s;
    s->next = p;    //新结点的next是第i个
     p->prior = s;    //第i-1个的next是新结点
    }
#else
    DuLinkList s, p = *L;    //p指向头结点
    int      pos  = 0;

    /* 寻找第i-1个结点 */
    while(p && pos<i-1) {
    p=p->next;
    pos++;
    }

    if (p==NULL || pos>i)  //i值非法则返回
    return ERROR;

    //执行到此表示找到指定位置,p指向第i-1个结点
    s = (DuLinkList)malloc(sizeof(DuLNode));
    if (s==NULL)
    return OVERFLOW;

    s->data = e;     //新结点数据域赋值
    s->next = p->next;  //新结点的next是第i个结点(即使p->next是NULL也没问题)
    if (p->next) //如果有第i个结点
        p->next->prior = s; //第i个结点的prior是s
    s->prior = p;       //s的前驱是p
    p->next = s;        //p的后继是s
#endif

    return OK;
}

/* 删除指定位置的元素,并将被删除元素的值放入e中返回 */
Status ListDelete(DuLinkList *L, int i, ElemType *e)
{
#if 1
    DuLinkList p = *L;    //p指向头结点
    int      pos  = 0;

    /* 寻找第i个结点(p是第i个结点) */
    while(p && pos<i) {
    p=p->next;
    pos++;
    }

    if (p==NULL || pos>i)    //i值非法则返回
    return ERROR;

    //执行到此表示找到了第i个结点,此时p指向第i个结点

    *e = p->data;      //取第i个结点的值
    p->prior->next = p->next;
    if (p->next) //要加判断条件
        p->next->prior = p->prior;
    free(p);           //释放第i个结点
#else
    DuLinkList q, p = *L;    //p指向头结点
    int      pos  = 0;

    /* 寻找第i个结点(p->next是第i个结点) */
    while(p->next && pos<i-1) {
    p=p->next;
    pos++;
    }

    if (p->next==NULL || pos>i-1)    //i值非法则返回
    return ERROR;

    //执行到此表示找到了第i个结点,此时p指向第i-1个结点

    q = p->next;       //q指向第i个结点
    p->next = q->next; //第i-1个结点的next域指向第i+1个(即使NULL也没错)
    if (q->next)
        q->next->prior = p;

    *e = q->data;      //取第i个结点的值
    free(q);           //释放第i个结点
#endif

    return OK;
}

/* 遍历线性表 */
Status ListTraverse(DuLinkList L, Status (*visit)(ElemType e))
{
    extern int line_count; //在main中定义的打印换行计数器(与算法无关)
    DuLinkList p = L->next;
    line_count = 0;        //计数器恢复初始值(与算法无关)

#if 1
    while(p && (*visit)(p->data)==TRUE) //同单链表
    p=p->next;

    if (p)
        return ERROR;

    printf("\n");//最后打印一个换行,只是为了好看,与算法无关
#else
    /* 逆序输出 */
    while(p->next) //同单链表
    p=p->next;

    /* 执行到此,p指向最后一个结点 */
    while(p && p->prior && (*visit)(p->data)==TRUE) //同单链表
    p=p->prior;

    printf("\n");//最后打印一个换行,只是为了好看,与算法无关
#endif

    return OK;
}

#include <stdio.h>
#include "linear_list_DL.h"

#define INSERT_NUM        115        //初始插入表中的元素数量
#define MAX_NUM_PER_LINE     10        //每行最多输出的元素个数

int line_count = 0;   //打印链表时的计数器

/* 用于比较两个值是否相等的具体函数,与LocateElem中的函数指针定义相同,调用时代入
   int LocateElem(sqlist L, ElemType e, Status (*compare)(ElemType e1, ElemType e2)) */
Status MyCompare(ElemType e1, ElemType e2)
{
    if (e1==e2)
        return TRUE;
    else
        return FALSE;
}

/* 用于访问某个元素的值的具体函数,与ListTraverse中的函数指针定义相同,调用时代入
   Status ListTraverse(sqlist L, Status (*visit)(ElemType e)) */
Status MyVisit(ElemType e)
{
    printf("%3d->", e);

    /* 每输出MAX_NUM_PER_LINE个,打印一个换行 */
    if ((++line_count)%MAX_NUM_PER_LINE == 0)
        printf("\n");

    return OK;
}

int main()
{
    DuLinkList L;
    ElemType   e1, e2;
    int        i, pos;

    InitList(&L);

    printf("空表=%s\n", (ListEmpty(L)==TRUE)?"TRUE":"FALSE");
    printf("表长=%d\n\n", ListLength(L));

    printf("插入%d个元素:\n", INSERT_NUM);
    for (i=INSERT_NUM*2; i>0; i-=2)
    ListInsert(&L, 1, i);
    ListTraverse(L, MyVisit);//此处传入MyVisit函数名

    printf("空表=%s\n", (ListEmpty(L)==TRUE)?"TRUE":"FALSE");
    printf("表长=%d\n\n", ListLength(L));

    /* 分别取第1、最后、以及小于第1、大于最后的4种情况下的的元素值、前驱值、后继值
       最后再加一个任意输入值 */
    for (i=0; i<5; i++) {
        int pos;
    switch(i) {
        case 0:
            pos = 1;
            break;
        case 1:
            pos = ListLength(L);
            break;
        case 2:
            pos = -1;
            break;
        case 3:
            pos = ListLength(L)+1;
            break;
        case 4:
        printf("请输入要取元素的位序[1..%d]:", ListLength(L));
        scanf("%d", &pos);
        break;
        }

        /* 取第1个元素以及前驱、后继 */
    if (GetElem(L, pos, &e1)==OK) {
        printf("第%d个元素=%d\n", pos, e1);

        /* 只有取得了某个元素,才能取前驱和后继 */
        if (PriorElem(L, e1, &e2)==OK)
        printf("第%d个元素(%d)的前驱=%d\n", pos, e1, e2);
        else
        printf("无法取得第%d个元素(%d)的前驱\n", pos, e1);

        if (NextElem(L, e1, &e2)==OK)
        printf("第%d个元素(%d)的后继=%d\n\n", pos, e1, e2);
        else
        printf("无法取得第%d个元素(%d)的后继\n\n", pos, e1);
        }
    else
        printf("无法取得第%d个元素\n\n", pos);
        } // end of for

    printf("请输入要查找的元素:\n");
    scanf("%d", &e1);
    if ((pos=LocateElem(L, e1, MyCompare))>0)       //此处传入MyCompare函数名
        printf("元素%d的位序=%d\n", e1, pos);
    else
        printf("找不到元素%d\n", e1);

    printf("\n请输入要插入元素的值:\n");
    scanf("%d", &e1);
    printf("请输入要插入元素的位序:\n");
    scanf("%d", &pos);
    if (ListInsert(&L, pos, e1)==OK) {
        printf("在%d前插入元素%d成功\n", pos, e1);
        printf("新表为:\n");
    ListTraverse(L, MyVisit);
        }
    else
        printf("在%d前插入元素%d失败\n", pos, e1);

    printf("\n请输入要删除元素的位序:\n");
    scanf("%d", &pos);
    if (ListDelete(&L, pos, &e1)==OK) {
        printf("删除第%d个元素=%d成功\n", pos, e1);
        printf("新表为:\n");
    ListTraverse(L, MyVisit);
        }
    else
        printf("删除第%d个元素失败\n", pos);

    printf("\n清空表:\n");
    ClearList(&L);
    printf("空表=%s\n", (ListEmpty(L)==TRUE)?"TRUE":"FALSE");
    printf("表长=%d\n", ListLength(L));

    DestroyList(&L);

    return 0;
}


阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页