数据结构:单链表的基本操作实现

实验内容

编程实现链表下教材第二章定义的线性表的基本操作,最好用菜单形式对应各个操作,使其编程一个完整的小软件。注意,每个功能模块一定要考虑非法的情况,并作出相应的提示,例如:求前驱,要分别能够测试第一个元素的前驱、其他正常的元素的前驱、输入一个在表中不存在的元素求其前驱,这三种情况应给出相应的提示语和结果值;插入和删除时要考虑插入或删除的位置是否合法等。

实验要求:

菜单项包括:

1.初始化或重置链表

2.销毁链表

3.清空链表

4.链表长度

5.指定位置的元素值

6.链表已存在元素的位序

7.求输入元素的直接前驱

8.求输入元素的直接后继

9.在第i个位置插入一个元素

10.删除第i个元素

11.输出有的链表元素

12.初始化并用头插法(或尾插法)输入元素

13.实现单链表的逆序存放

要求:所有的提示语和输出语句不允许出现在自定义的函数中,只能在main函数中出现提示语。

注:销毁链表时需要循环释放每个结点所占用的空间。

注:求前驱是指,输入一个元素值(而不是位置),求该元素在顺序表中的直接前驱元素值。求后继是指:输入一个元素值(而不是位置),求该元素在顺序表中的直接后继元素值。

一、设计思想

  1. 结构体的定义:首先,这段代码定义了一个叫LNode的结构体,表示链表节点。每个节点都包含一个data(后续我们会将一些值储存在这里)和一个指向下一个节点的指针。此外,还有一个is_initialized标志,用于标识该节点是否被初始化。
  2. 链表操作的函数
    • Initialize_reset_linklist:这个函数用于初始化或重置链表。它首先分配内存给头结点,然后设置头结点的next指针指向NULL,最后返回该头结点。
    • Destroy_linklist:这个函数会销毁整个链表,包括头结点。它会遍历链表,释放每个节点占用的内存。
    • Clear_linklist:清空链表中除了头结点之外的所有节点。
    • Length_linklist:返回链表的长度。
    • Data_linklist:根据给定位置查找元素。
    • Order_linklist:查找某元素在链表中的位置。
    • Before_linklist和After_linklist:分别用于查找某元素的前驱和后继。
    • Insert_linklist:在某个位置插入新的元素。
    • Delete_linklist:删除某个位置的元素。
    • Print_linklist:遍历链表并打印所有元素。
    • Initialize_Tail_interpolation_linklist:采用尾插法初始化链表。
    • Reverse_linklist:将链表逆序存放。

二、主要源代码

#define _CRT_SECURE_NO_WARNINGS 1 

#include<stdlib.h>//malloc需用库函数
#include<stdio.h>

typedef int Elemtype;

typedef struct LNode
{
	Elemtype data;
	struct LNode* next;
	int is_initialized;
}LNode, * Linklist;

Linklist Initialize_reset_linklist()//1
{
	LNode* p, * q, * head;
	head = (LNode*)malloc(sizeof(LNode));//为头结点分配内存
	if (head == NULL) {
		printf("内存分配失败!\n");
		return NULL;
	}
	head->next = NULL;//头结点的下一个节点为空
	q = head;//q指针初始化
	head->is_initialized = 1;
	printf("初始化完成!\n");
	return head;//返回头结点的指针
}

void Destroy_linklist(LNode* head)//2  包含单向链表的头结点在内,销毁单向链表的所有结点
{
	if (head == NULL || !(head->is_initialized))
	{
		printf("链表还未初始化,无法销毁!\n");
		return;
	}
	LNode* p = head;
	LNode* q = NULL;//声明两个指针变量p和q
	while (p != NULL)
	{
		q = p;//分别指向链表的头节点和当前节点
		p = p->next;
		free(q);//释放q指向的节点的内存空间
		q = NULL;
	}
	printf("销毁成功!\n");
}

void Clear_linklist(LNode* head)//3  清空除了头结点之外的所有结点的数据域和指针域
{
	if (head == NULL || !(head->is_initialized))
	{
		printf("链表还未初始化,无法清空!\n");
		return;
	}
	LNode* p = head->next;
	LNode* temp = head;
	LNode* q = NULL;
	while (p != NULL)
	{
		q = p;
		p = p->next;
		free(q);
		q = NULL;
	}
	printf("清空成功!\n");
}

int Length_linklist(const LNode* head)// 4
{
	if (head == NULL || !(head->is_initialized))
	{
		printf("链表还未初始化,无法计算长度!\n");
		return -1;
	}
	int length = head->data;
	return length;
}

void Data_linklist(const LNode* head)//  5
{
	if (head == NULL || !(head->is_initialized))
	{
		printf("链表还未初始化,无法查找!\n");
		return;
	}

	int pos = 0;
	printf("请输入你要查找链表中的第几位元素:\n");
	if (scanf("%d", &pos) != 1) {
		printf("输入错误!\n");
		return;
	}
	LNode* p;
	p = head;
	if (pos > 0 && pos <= head->data)
	{
		int i = 1;
		while (i < pos + 1)
		{
			p = p->next;
			i++;
		}
		printf("第%d位元素的值为:%d\n", pos, p->data);
	}
	else
		printf("输入位置有误,请重新输入!\n");

}

void Order_linklist(const LNode* head)//6
{
	if (head == NULL || !(head->is_initialized))
	{
		printf("链表还未初始化,无法查找!\n");
		return;
	}
	printf("请输入你想查询次序的元素:\n");
	Elemtype elem = 0;
	if (scanf("%d", &elem) != 1) {
		printf("输入错误!\n");
		return;
	}

	LNode* p = head->next;
	int i = 1;
	while (p != NULL)
	{
		if (p->data == elem)
		{
			printf("元素%d在链表中的位置是:%d\n", elem, i);
			return;
		}
		i++;
		p = p->next;
	}
	printf("元素%d在链表中不存在。\n", elem);
}

void Before_linklist(const LNode* head)//7
{
	if (head == NULL || !(head->is_initialized))
	{
		printf("链表还未初始化,无法查找!\n");
		return;
	}
	printf("请输入元素的值,程序将输出该元素的直接前驱元素值\n");
	int temp = 0;
	int flag = 1;
	if (scanf("%d", &temp) != 1) {
		printf("输入错误!\n");
		return;
	}
	int temp_old = 0;
	LNode* p = head->next;
	while (flag)
	{
		if (temp == p->data)
		{
			flag = 0;
		}
		else
		{
			temp_old = p->data;
			p = p->next;
		}

	}
	printf("该元素的直接前驱元素值为:%d\n", temp_old);
}

void After_linklist(const LNode* head)//8
{
	if (head == NULL || !(head->is_initialized))
	{
		printf("链表还未初始化,无法查找!\n");
		return ;
	}
	printf("请输入元素的值,程序将输出该元素的直接后继元素值\n");
	int temp = 0;
	if (scanf("%d", &temp) != 1) {
		printf("输入错误!\n");
		return ;
	}
	LNode* p = head->next;
	while (p != NULL)
	{
		if (temp == p->data)
		{
			if (p->next != NULL) 
			{
				printf("该元素的直接后继元素值为:%d\n", p->next->data);
			}
			else {
				printf("该元素没有直接后继元素!\n");
				return ;
			}
		}
		p = p->next;
	}
}

void Insert_linklist(LNode* head)//9
{
	if (head == NULL || !(head->is_initialized))
	{
		printf("链表还未初始化,无法插入!\n");
		return;
	}
	printf("请输入你要插入元素的位置:\n");
	int pos = 0;
	if (scanf("%d", &pos) != 1) {
		printf("输入错误!\n");
		return;
	}
	printf("请输入你要插入的元素:\n");
	Elemtype elem;
	if (scanf("%d", &elem) != 1) {
		printf("输入错误!\n");
		return;
	}
	LNode* p = head;
	int i = 1;
	while (p != NULL && i < pos)
	{
		p = p->next;
		i++;
	}
	if (p == NULL && i < pos) {
		printf("插入位置超出链表长度!\n");
		return;
	}
	LNode* d = (LNode*)malloc(sizeof(LNode));// 创建新节点
	if (d == NULL) {
		printf("内存分配失败!\n");
		return;
	}
	d->data = elem;                            
	d->next = p->next;                        
	p->next = d;                               
	printf("插入成功!\n");
}

void Delete_linklist(LNode* head)//10
{
	if (head == NULL || !(head->is_initialized))
	{
		printf("链表还未初始化,无法删除!\n");
		return;
	}
	printf("请输入你要删除的元素的位置:\n");
	int pos = 0;
	if (scanf("%d", &pos) != 1) {
		printf("输入错误!\n");
		return;
	}

	LNode* p = head;
	int i = 0;
	while (p != NULL && i < pos - 1)
	{
		p = p->next;
		i++;
	}
	if (p->next != NULL)
	{
		LNode* q = p->next;
		p->next = q->next;
		free(q);
		q = NULL;
	}
	printf("删除成功!\n");
}

void Print_linklist(const LNode* head)//11
{
	if (head == NULL || !(head->is_initialized))
	{
		printf("链表还未初始化,无法输出!\n");
		return;
	}
	LNode* p = head->next;
	while (p != NULL)
	{
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}

Linklist Initialize_Tail_interpolation_linklist()
{
	LNode* p, * q, * head;
	head = (LNode*)malloc(sizeof(LNode)); //为头结点分配内存
	if (head == NULL) {
		printf("内存分配失败!\n");
		return NULL;
	}
	head->next = NULL; //头结点的下一个节点为空
	q = head; //q指针初始化
	printf("请输入要创建的链表长度:\n");
	int length = 0;
	if (scanf("%d", &length) != 1) {
		printf("输入错误!\n");
		return NULL;
	}
	head->data = length; //将链表的长度存储在头结点的数据域之中

	for (int i = 0; i < length; i++)
	{
		p = (LNode*)malloc(sizeof(LNode)); //对每个新节点都分配空间
		if (p == NULL) {
			printf("内存分配失败!\n");
			return NULL;
		}
		printf("请输入链表的第%d个元素的数据:\n", i + 1);
		if (scanf("%d", &(p->data)) != 1) {
			printf("输入错误!\n");
			return NULL;
		}
		p->next = NULL; //新节点的下一个节点设置为NULL
		q->next = p; //插入新节点
		q = p; //更新q节点
	}
	printf("创建成功!\n");
	return head; //返回头结点的指针
}

Linklist Reverse_linklist(LNode* head)//13
{
	if (head == NULL || !(head->is_initialized))
	{
		printf("链表还未初始化,无法逆序!\n");
		return NULL;
	}
	LNode* p = head->next;
	LNode* q = NULL;
	LNode* r = NULL;
	while (p != NULL)
	{
		r = q;
		q = p;
		p = p->next;
		q->next = r;
	}
	head->next = q;
	printf("逆序成功!\n");
	Print_linklist(head);
	return head;
}


void menu()
{
	printf("****------------------指令菜单-------------------****\n");
	printf("****      1.初始化或重置链表                     ****\n");
	printf("****      2.销毁链表                             ****\n");
	printf("****      3.清空链表                             ****\n");
	printf("****      4.链表长度                             ****\n");
	printf("****      5.指定位置的元素值                     ****\n");
	printf("****      6.链表已存在元素的位序                 ****\n");
	printf("****      7.求输入元素的直接前驱                 ****\n");
	printf("****      8.求输入元素的直接后继                 ****\n");
	printf("****      9.在第i个位置插入一个元素              ****\n");
	printf("****     10.删除第i个元素                        ****\n");
	printf("****     11.输出有的链表元素                     ****\n");
	printf("****     12.初始化并用头插法(或尾插法)输入元素 ****\n");
	printf("****     13.实现单链表的逆序存放                 ****\n");


}

int main()
{
	int input = 0;
	int pos;
	Linklist linklist = NULL;
	menu();
	do
	{
		printf("请输入要选择的指令:\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			linklist = Initialize_reset_linklist();
			break;
		case 2:
			Destroy_linklist(linklist);
			linklist = NULL;
			break;
		case 3:
			Clear_linklist(linklist);
			break;
		case 4:
			if (Length_linklist(linklist) >= 0)
				printf("链表长度:%d\n", Length_linklist(linklist));
			break;
		case 5:
			Data_linklist(linklist);
			break;
		case 6:
			Order_linklist(linklist);
			break;
		case 7:
			Before_linklist(linklist);
			break;
		case 8:
			After_linklist(linklist);
			break;
		case 9:
			Insert_linklist(linklist);
			break;
		case 10:
			Delete_linklist(linklist);
			break;
		case 11:
			Print_linklist(linklist);
			break;
		case 12:
			linklist = Initialize_Tail_interpolation_linklist();
			break;
		case 13:
			linklist = Reverse_linklist(linklist);
			break;
		default:
			printf("无效的指令,请重新输入!\n");
			break;
		}
	} while (input != 0);

	return 0;
}

验收/测试用例

  1. 没有初始化前进行其他操作,程序是否能控制住;

  1. 销毁链表
  2. 清空链表

  1. 链表长度
  2. 指定位置的元素值
  3. 链表已存在元素的位序
  4. 初始化并用头插法(或尾插法)输入元素
  5. 实现单链表的逆序存放
  6. 输出有的链表元素
  7. 删除第i个元素
  8. 求输入元素的直接前驱

  1. 求输入元素的直接后继
  2. 在第i个位置插入一个元素

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值