带头结点的双向循环链表操作集

分数 50

作者 伍建全

单位 重庆科技大学

本题要求实现一个带头结点的双向循环链表操作集。

函数接口定义:

typedef int dataType;

typedef struct _node
{
    dataType data;
    struct _node *prev;//指向前驱的指针
    struct _node *next;//指向后继的指针
}node;

typedef node* List;

//创建一个空的循环链表,返回指向头节点的指针。
List create_list();
//用尾插法向链表L中插入数据域等于x的结点
void insert(List L, dataType x);
//如果链表为空,则返回true,否则返回false。
bool is_empty(List L);
//顺序遍历链表L。输出所有结点的数据域。如果链表为空则输出NULL
void traverse(List L);
//逆序遍历链表L。输出所有结点的数据域。如果链表为空则输出NULL
void traverse_back(List L);
//返回第1个指向数据域等于x的结点的指针。如果没有则返回NULL。
node* search(List L, dataType x);
//删除指针p指向的结点。调用者保证p是合法的。
//返回p指向结点后继结点的指针。
//若p指向链表最后一个结点,返回指向头结点的指针。
node* delete_node(List L, node* p);
//删除链表L中所有数据域等于x的结点
void remove_node(List L, dataType x);
//使链表L成为一个空链表
void make_empty(List L);
//销毁链表L
void destroy_list(List L);

裁判测试程序样例:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

typedef int dataType;

typedef struct _node
{
    dataType data;
    struct _node *prev;//指向前驱的指针
    struct _node *next;//指向后继的指针
}node;

typedef node* List;

//创建一个空的循环链表,返回指向头节点的指针。
List create_list();
//用尾插法向链表L中插入数据域等于x的结点
void insert(List L, dataType x);
//如果链表为空,则返回true,否则返回false。
bool is_empty(List L);
//顺序遍历链表L。输出所有结点的数据域。如果链表为空则输出NULL
void traverse(List L);
//逆序遍历链表L。输出所有结点的数据域。如果链表为空则输出NULL
void traverse_back(List L);
//返回第1个指向数据域等于x的结点的指针。如果没有则返回NULL。
node* search(List L, dataType x);
//删除指针p指向的结点。调用者保证p是合法的。
//返回p指向结点后继结点的指针。
//若p指向链表最后一个结点,返回指向头结点的指针。
node* delete_node(List L, node* p);
//删除链表L中所有数据域等于x的结点
void remove_node(List L, dataType x);
//使链表L成为一个空链表
void make_empty(List L);
//销毁链表L
void destroy_list(List L);

int main()
{
    int x;
    List mylist = create_list();
    //输入一系列正整数,输入0表示输入结束
    //用尾插法插入链表
    scanf("%d", &x);
    while (x != 0)
    {
        insert(mylist, x);
        scanf("%d", &x);
    }
    //顺序遍历链表
    traverse(mylist);
    //逆序遍历链表
    traverse_back(mylist);
    //输入要删除的结点数据域
    scanf("%d", &x);
    node *p = search(mylist, x);
    if (p != NULL)
    {
        delete_node(mylist, p);
    }
    //顺序遍历链表
    traverse(mylist);
    //逆序遍历链表
    traverse_back(mylist);
    //输入要删除的结点数据域
    scanf("%d", &x);
    remove_node(mylist, x);
    //顺序遍历链表
    traverse(mylist);
    //逆序遍历链表
    traverse_back(mylist);
    //销毁链表
    destroy_list(mylist);
    return 0;
}

/* 请在这里填写答案 */

输入样例:

在这里给出一组输入。例如:

10 20 10 10 20 30 0
20
10

输出样例:

在这里给出相应的输出。例如:

10 20 10 10 20 30 
30 20 10 10 20 10 
10 10 10 20 30 
30 20 10 10 10 
20 30 
30 20 

输入输出样例解释:

程序首先创建一个空的双向循环链表,如下图所示:

捕获3.PNG

输入的第1行是

10 20 10 10 20 30 0

此时程序创建一个带头节点的双向循环链表,如下图所示:

捕获.PNG


此时顺序输出

10 20 10 10 20 30

逆序输出

30 20 10 10 20 10

输入的第2行是

20

此时程序删除从头结点向后的第1个数据域等于20的结点,所以链表如下图所示:

捕获1.PNG


此时顺序输出

10 10 10 20 30

逆序输出

30 20 10 10 10

输入的第3行是

10

此时程序删除链表中所有数据域等于10的结点,所以链表如下图所示:

捕获2.PNG

此时顺序输出

20 30

逆序输出

30 20

代码长度限制

16 KB

时间限制

2500 ms

内存限制

128 MB

C程序如下:

List create_list() {
    List newnode = (List)malloc(sizeof(node));
    if (newnode == NULL) {
        exit(EXIT_FAILURE);
    }
    newnode->next = newnode;//头结点的next域指向自己
    newnode->prev = newnode;//头结点的prev域指向自己
    return newnode;//返回该头结点
}
void insert(List L, dataType x) {
    List p;
    p = (List)malloc(sizeof(node));//向内存申请一片空间
    p->data = x;//给新链表的数据域赋值
    List pTail = L->prev;//定义一个指针指向链表的尾巴
    p->prev = pTail;//让新的链表与原链表的尾结点链接
    pTail->next = p;
    p->next = L;//让新结点与原链表的头结点链接
    L->prev = p;
}
bool is_empty(List L) {
    List p = L;//定义一个指针p指向该链表的头结点
    if (p->next == L && p->prev == L) {
        return true;//如果该链表的next域和prev域都指向该链表的头结点
    }//则说明该链表为空返回true
    else {
        return false;//否则不为空返回false
    }
}
void traverse(List L) {
    List p = L;
    if (is_empty(p)) {
        printf("NULL");
    }
    p = L->next;//定义一个指针p指向第一个数据域
    while (p != L) {//顺序遍历这个单链表
        printf("%d ", p->data);//输出单链表中每个数据的值
        p = p->next;//p指针向后移动到下一个结点
    }
    printf("\n");
}
void traverse_back(List L) {
    List p = L;
    if (is_empty(p)) {
        printf("NULL");
    }
    p = L->prev;//定义一个指针p指向L链表的最后一个数据域
    while (p != L) {//逆序遍历这个单链表
        printf("%d ", p->data);//输出每一个结点的数据域
        p = p->prev;//p指针指向该结点的前一个结点
    }
    printf("\n");
}
node* search(List L, dataType x) {
    List p = L;//定义一个指针指向该单链表的头结点
    if (is_empty(p)) {//如果该链表为空
        return NULL;//返回NULL
    }
    p = L->next;//否则p指向单链表的第一个数据域
    while (p->data != x)//遍历这个单链表直到找到对应的数据
    {
        p = p->next;
        if (p == L) {
            return NULL;//如果遍历完没找到则返回NULL
        }
    }
    return p;//找到后返回该指针
}
node* delete_node(List L, node* p) {
    List q = L ->next;//定义一个指针指向单链表的第一个数据域
    while (q != p) {//遍历这个单链表直到找到对应指针所指向的结点
        q = q->next;
    }
    q->prev->next = q->next;//让需要删除结点的前一个结点与需要删除结点的后一个结点连接
    q->next->prev = q->prev;
    free(q);//释放需要删除结点的空间
}
void remove_node(List L, dataType x) {
    List pHead, q, pFree;//定义三个指针
    pHead = L;//pHead保存头指针的地址
    pFree = L->next;//用于删除的指针指向单链表的第一个数据域
    q = pFree->next;//q指针指向pFree指针的下一个结点
    while (pFree != pHead) {//遍历单链表
        if (pFree->data == x) {//找到要删除的结点
            pFree->prev->next = pFree->next;//让要删除结点的前一个结点与后一个结点链接
            pFree->next->prev = pFree->prev;//后一个结点即q指针所指向的结点
            free(pFree);//释放需要删除的结点
        }
        pFree = q;//pFree指向下一个结点
        q = pFree->next;//q继续向后指
    }
}
void make_empty(List L) {
    List p, q;
    p = L;//定义一个指针p指向链表的头结点
    q = L->next;//q指向链表的第一个数据域
    while (q != L)//遍历整个链表
    {
        p->next = q->next;//让头结点与要释放的结点的下一个结点链接
        q->next->prev = p;
        free(q);//释放该节点
        q = p->next;//指向下一个需要释放的结点
    }
}
void destroy_list(List L) {
    List p, q;
    p = L;//定义一个指针p指向链表的头结点
    q = p->next;//q指向链表的第一个数据域
    while (q != L)//遍历整个链表
    {
        p->next = q->next;//让头结点与要释放的结点的下一个结点链接
        q->next->prev = p;
        free(q);//释放该节点
        q = p->next;//指向下一个需要释放的结点
    }
    free(p);//释放头结点
}
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值