题目:
利用尾插法建立一个单链表,并从屏幕显示单链表元素列表;根据屏幕上的提示进行单链表的删除、插入等操作。
运行环境:Dev-C++ 5.11
下面是正式的代码,这里没有拆分成多个文件,直接堆在一起了。
/* 单链表程序
包含结构体:
1. 定义单链表结构(结点)
包含函数:
1. 获取链表的指定位置的结点
2. 创建一个单链表
3. 插入节点
4. 输出已有的单链表信息
5. 按序号删除结点
6. 按序号查询结点
7. 提示框函数(负责调用上面5个函数)
8. 释放结点内存空间
*/
#include<stdio.h>
#include<stdlib.h>
#define SIZE sizeof(LinkList)
// 定义单链表的结构(结点)
typedef struct Node{
int data; // 数据域
struct Node *next; // 指针域
}LinkList;
// 全局变量n用来存储链表结点的个数,也方便输出提示信息
int n;
// 1. 移动指针到想要的位置,返回从此位置开始的结点指针类型变量
LinkList* remove(LinkList* head, int i) {
LinkList* p;
int j=0;
p = head;
while((j < i) && (p->next != NULL)){
p = p->next;
j++;
}
if(j == i)
return p;
else
return NULL;
}
// 2.创建一个空的单链表,并对其进行赋值,返回单链表的头结点的指针
LinkList* creat() {
LinkList *head;
LinkList *p1, *p2;
n = 0;
printf("请输入数值(输入数值时,输入'0'并回车可以退出输入)\n");
p1 = p2 = (LinkList *)malloc(SIZE);
printf("第%d个数值:",n+1);
scanf("%d",&p1->data); // 开始输入第一个结点的数值
head = p1; // 头结点指向首元结点
// 如果用户输入的数值不是0
while (p1->data != 0) {
n += 1; // 结点数+1
p1 = (LinkList*)malloc(SIZE); // 再创建一个结点,并让p1指向它
p2->next = p1; // 把新创建的结点同其前一个结点连接起来
p2 = p1; // p2指向新创建的结点
printf("第%d个数值:",n+1); // 输出提示信息
scanf("%d",&p1->data);
}
// 如果用户输入的数值是0(默认表示输入结束,或者用户不想再继续输入)
p2->next = NULL; // p2就是尾结点
return head; // 返回头结点的指针
}
// 3. 插入结点
LinkList* insert(LinkList *head) {
LinkList *p, *s;
int i; // i用来存放插入结点的位置
int num; // num用来存放插入的数值
printf("请输入插入结点的位置:");
scanf("%d", &i);
p = remove(head, i-2); // 调用remove函数,获取一个结点的位置,这个结点是被插入结点的前一个结点
if(p == NULL) // 保证程序稳健性
printf("出错:插入位置错误。请重新输入\n");
else {
printf("请输入插入的数值:");
scanf("%d", &num);
s = (LinkList*)malloc(SIZE); // 给s指针开辟内存空间
s->data = num; // 给被插入结点赋值
s->next = p->next; // 让s指向被插入结点的后一个结点
p->next = s; // 让s指向被插入结点的前一个结点
}
return head; // 返回头结点
}
// 4. 输出链表中所有的数值
void print(LinkList *head) {
int n = 1; // 局部变量n
LinkList *p;
p = head;
printf("\n已输入的内容:\n");
if(head != NULL) // 如果链表非空
do {
printf("第%d个数值是:%d\n",n, p->data);
p = p->next;
n += 1;
}while(p!=NULL);
else
printf("出错:此链表为空链表");
}
// 5. 按序号删除结点
LinkList* del(LinkList *head) {
LinkList *p1, *p2;
int num;
printf("请输入被删除结点的序号: ");
scanf("%d", &num);
p1 = remove(head, num-2); // p1指向被删除结点的前一个结点
if(p1 == NULL)
printf("出错:输入序号错误。请重新输入\n"); // 保证程序稳健性
else {
p2 = (LinkList*)malloc(SIZE); // 给p2开辟内存空间
p2 = p1->next; // 让p2指向被删除结点
p1->next = p2->next; // 将p1和p2之后的下一个结点连接起来
free(p2); // 释放p2的内存空间
p2 = NULL; // 给p2赋值为NULL
}
return head;
}
// 6. 按序号查询结点
void search(LinkList *head) {
LinkList *p;
int num;
printf("请输入需要查询的结点的序号: ");
scanf("%d", &num);
p = head;
if(p == NULL||num>n) // 保证程序稳健性
printf("链表不存在或者输入的序号不正确,请重新输入");
else {
while(num -= 1) { // 当num为1时,p结点指向被查询结点
p = p->next;
}
printf("查询结点数据为: %d\n", p->data);
}
}
// 7. 释放结点内存空间
void free(LinkList* head) {
LinkList * p;
while(head != NULL) {
p = head;
head = head->next;
free(p);
p = NULL; // 给p指针赋值为NULL是一个好习惯
}
printf("链表已被释放");
}
// 8. 提示框函数(负责调用以上7个函数)
void menu() {
int num;
LinkList *head;
printf("+———— 单链表选择菜单 ————+\n");
printf("| 1.创建一个单链表(并初始化数值) |\n");
printf("| 2.插入一个结点 |\n");
printf("| 3.输出已有的单链表的结点信息 |\n");
printf("| 4.按序号删除结点 |\n");
printf("| 5.按序号查询结点 |\n");
printf("| 6.释放链表空间并退出 |\n");
printf("+————————————————————+\n");
while(num) {
printf("\n请输入需要进行的操作: ");
scanf("%d", &num);
switch(num) {
case 1:head = creat();print(head);system("pause");break;
case 2:head = insert(head);system("pause");break;
case 3:print(head);system("pause");break;
case 4:head = del(head);system("pause");break;
case 5:search(head);system("pause");break;
case 6:free(head);system("pause");break;
default:printf("未输入正确的数字,请重新输入\n");
}
}
}
// 主函数,只调用提示框函数
int main() {
menu();
return 0;
}