分数 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
输入输出样例解释:
程序首先创建一个空的双向循环链表,如下图所示:
输入的第1行是
10 20 10 10 20 30 0
此时程序创建一个带头节点的双向循环链表,如下图所示:
此时顺序输出
10 20 10 10 20 30
逆序输出
30 20 10 10 20 10
输入的第2行是
20
此时程序删除从头结点向后的第1个数据域等于20的结点,所以链表如下图所示:
此时顺序输出
10 10 10 20 30
逆序输出
30 20 10 10 10
输入的第3行是
10
此时程序删除链表中所有数据域等于10的结点,所以链表如下图所示:
此时顺序输出
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);//释放头结点
}