一、实验目的和要求
目的:
- 熟悉单链表的创建,取值,查找,插入,删除等操作。
要求:
- 初始化单链表La
- 在La中插入一个新结点
- 删除La中某个结点
二、实验内容
(1)单链表中插入结点
插入结点有两种方法,一种头插,一种尾插
头插法:从空表开始,重复读入数据,生成新结点,将读入的数据存放到新结点的数据域中,然后将新结点插入到当前链表的头结点之后,直至读入结束标志为止,头插法创建链表的根本在于最后两条语句:
node->next = head->next;
//将头指针所指向的下一个结点的地址,赋给新创建结点的next
head->next= node;
//将新创建的结点的地址赋给头指针的下一个结点
尾插法:将新结点插到当前单链表的表尾处
end->next = node;
//将新开辟的node的地址赋给head的下一个结点地址
end = node;
//将新建的结点node的地址赋给尾结点end
(2)单链表中删除结点
ListDelete (&L, i, &e):删除单链表L的第i个结点,将结点元素值赋给e。
利用循环操作将p指针定位到第i-1个元素位置,用q指针指向第i个结点 位置并将元素值赋给e,让第i-1个元素的指针域指向第i+1个元素,然后 释放q结点;单链表的删除标准语句序列为:
- q = p->next;
- p->next = q->next;
- e = q->data;
三、依据的基本原理
整个程序的流程看主函数,具体函数实现过程请看第四点,为方便讲解,我直接在代码后通过注释的方式讲解原理:
int main(int argc, int argv[]) #定义主函数
{
int opt = 0; #定义变量opt
int num = 0; #定义变量num
//创建链表
printf("请创建一个链表:\n");
pNode phead = create_list(); #运行自定义的创建链表函数
//打印输出链表
printf("打印输出链表:\n");
traverse_list(phead); #运行自定义的输出链表函数
//在数字key前边插入数字data
int key; #定义变量key
int data; #定义变量data
Node node;
printf("在数字几前插入:\n");
scanf("%d",&data); #输入
printf("输入你想要插入的数字:\n");
scanf("%d",&key); #输入想插入的数字
insertnode_bypre(phead,node,key,data); #运行自定义的插入函数
traverse_list(phead); #运行自定义的输出链表函数
//在数字key1后边插入数字data1
int key1;
int data1; #定义变量
Node node1;
printf("在数字几后插入:\n");
scanf("%d",&data1);
printf("输入你想要插入的数字:\n");
scanf("%d",&key1);
insertnode_byback(phead,node,key1,data1); #后插法
traverse_list(phead); #运行自定义的输出链表函数
//删除节点
int deldata;
printf("删除数字:\n");
scanf("%d",&deldata);
deletenode(phead, deldata); #运行自定义的删除结点函数
traverse_list(phead); #运行自定义的输出链表函数
//查找数字,输出位置
printf("输入想要查找的数字:\n");
scanf("%d",&num);
searchnode(phead,num); #运行自定义的按值查找函数
return 0;
}
总的来说,该程序先创建一个链表,用户可根据需要选择创建的链表长度,并给链表赋值,创建成功后,输出链表.
然后分别使用前插法与后插法插入数据随后删除数据.
最后查找某个数据所在的位置.至此,程序结束.
四、实验步骤
这是一个用结构体写的程序,拆开,会很好理解.
程序一开始,就用结构体定义结点,把struct Node *定义为新类型pNode,是一个结构体的指针。随后,自定义了7个函数,分别是初始化一个链表结点, 创建链表函数, 遍历链表, 按值查找操作, 前插法, 后插法, 删除结点.
为了便于读者理解,我还是通过注释的方式进行讲解:
//(1)初始化一个链表结点
pNode init_node(Node *pnode, int data)
{
pnode = (Node *)malloc(sizeof(Node));
pnode -> data = data;//初始化数字域
pnode -> next = NULL;//初始化指针域
return pnode;
}
//创建链表函数
pNode create_list()
{
int i; // 用于下面循环
int len; // 用来存放有效节点的字数
int val; // 用于临时存放用户输入的数据
pNode pHead = (pNode)malloc(sizeof(Node)); // 分配一个不存放有效数据的头结点
pNode pTail = pHead; //链表的最后一个节点
pTail->next = NULL; // 最后一个节点的指针置为空
printf("请输入节点个数:");
scanf("%d", &len);
for (i = 0; i < len; i++)
{
printf("第 %d 个节点的数值:", i + 1);
scanf("%d", &val);
pNode pNew = (pNode)malloc(sizeof(Node)); //为节点分配空间
//将用户输入的数据赋给节点的成员,将最后一个节点的指针指向
//下一个新的节点,将新节点中的指针置为空,将新节点赋给最后的一个节点
pNew -> data = val; //将用户输入的数据赋给节点的成员
pTail -> next = pNew; //将最后一个节点的指针指向下一个新的节点
pNew -> next = NULL; //将新节点中的指针置为空
pTail = pNew; //将新节点赋给最后的一个节点
printf("successful!");
}
return pHead; //返回头节点
}
//(2)在链表中插入一个新结点。
//前插法
pNode insertnode_bypre(Node *phead, Node node,int data,int key)
{
Node *pnode = init_node(&node, data);//初始化插入的结点
Node *ptmp = phead;
if (phead == NULL)//链表为空,直接返回初始化的值
{
return pnode;
}
else if (phead->data == key)//处理的第一个结点是否为目标结点
{
phead = pnode;
pnode->next = ptmp;
}
else
{
while((ptmp->next != NULL) && (ptmp->next->data != key))
{
ptmp = ptmp->next;
}
if (ptmp->next == NULL)//没有找到的情况
{
printf("insert key NOT FOUND\n");
}
else//把新结点插入到目标结点的前面
{
ptmp = (Node *)malloc(sizeof(Node)); //分配一个Node类型大小的内存空间,并把分配空间的首地址强制转换成Node *类型的
ptmp->data = data; // 为新结点的数据域赋值
ptmp->next = phead->next; // 将头指针所指向的下一个结点的地址,赋给新创建结点的next
phead->next = ptmp; // 将新创建的结点的地址赋给头指针的下一个结点
}
}
printf("successful!");
return phead;
}
//后插法
pNode insertnode_byback(Node *phead,Node node ,int data,int key)
{
Node *pnode = init_node(&node, data);//初始化插入的结点
Node *ptmp = searchnode(phead,key);//查找目标结点
if (ptmp == NULL)//链表为空,或者没有找到
{
printf("Link is empty or not found key!\n");
return phead;
}
if (ptmp->next == NULL)//如果key为最后一个结点
{
ptmp->next = pnode;
}
else//将新结点插入到目标结点的后面
{
ptmp = (Node *)malloc(sizeof(Node)); //分配一个Node类型大小的内存空间,并把分配空间的首地址强制转换成Node *类型的
ptmp -> next = NULL; // 初始化头结点指向的下一个地址为 NULL
phead -> next = ptmp;
phead = phead->next;
}
printf("successful!");
return phead;
}
// (3)删除链表中的某一个结点。
pNode deletenode(Node *phead, int key)
{
Node *ptmp = phead;
Node *tmp = NULL;
if (phead == NULL)//处理链表为空的情况
{
printf("Link is empty,delete fail!\n");
return NULL;
}
else if(phead->data == key)//单独处理第一个结点
{
phead = phead->next;
free(ptmp); //释放目标结点
ptmp = NULL;
}
else
{
while (ptmp->next != NULL && ptmp->next->data != key)//没找&&没有找到
{
ptmp = ptmp->next;
}
if (ptmp->next == NULL)//没有找到
{
printf("delete key is not found!\n");
return phead;
}
if (ptmp->next->data == key)//找到目标结点并删除
{
tmp = ptmp->next;
ptmp->next = tmp->next;
free(tmp); //释放目标结点
tmp = NULL;
}
}
printf("successful!");
return phead;
}
// (4)在链表中查找某结点并返回其位置。
pNode searchnode(Node *phead,int key)
{
Node *ptmp = phead;
int i = 0;
if (ptmp == NULL) //查找结点,判断该结点是否存在
{
return NULL;
}
while (ptmp->data != key && ptmp->next != NULL)
{
i=i+1;
ptmp = ptmp->next;
}
if (ptmp -> data == key)
{
printf("所在位置为:%d\n",i);
return 0;
}
if (ptmp->next == NULL)
{
printf("该数字不在链表中\n");
return NULL;
}
}
//(5)打印输出链表中的结点元素值。
void traverse_list(pNode pHead)
{
pNode p = pHead->next; //将头节点的指针给予临时节点p
while (NULL != p) //节点p不为空,循环
{
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
五、实验结果及分析
六、附录(程序源码)
#include <stdio.h>
#include <stdlib.h>
typedef struct node{ //用结构体定义结点
int data;
struct node *next;
}Node, *pNode; //把struct Node *定义为新类型pNode,是一个结构体的指针。
//初始化一个链表结点
pNode init_node(Node *pnode, int data);
//创建链表函数
pNode create_list();
//遍历链表
void traverse_list(pNode pHead);
//按值查找操作
pNode searchnode(Node *phead, int key);
//前插法
pNode insertnode_bypre(Node *phead, Node node, int data, int key);
//后插法
pNode insertnode_byback(Node *phead, Node node, int data, int key);
//删除结点
pNode deletenode(Node *phead, int key);
//(1)初始化一个链表结点
pNode init_node(Node *pnode, int data)
{
pnode = (Node *)malloc(sizeof(Node));
pnode -> data = data;//初始化数字域
pnode -> next = NULL;//初始化指针域
return pnode;
}
//创建链表函数
pNode create_list()
{
int i; // 用于下面循环
int len; // 用来存放有效节点的字数
int val; // 用于临时存放用户输入的数据
pNode pHead = (pNode)malloc(sizeof(Node)); // 分配一个不存放有效数据的头结点
pNode pTail = pHead; //链表的最后一个节点
pTail->next = NULL; // 最后一个节点的指针置为空
printf("请输入节点个数:");
scanf("%d", &len);
for (i = 0; i < len; i++)
{
printf("第 %d 个节点的数值:", i + 1);
scanf("%d", &val);
pNode pNew = (pNode)malloc(sizeof(Node)); //为节点分配空间
//补充代码,将用户输入的数据赋给节点的成员,将最后一个节点的指针指向
//下一个新的节点,将新节点中的指针置为空,将新节点赋给最后的一个节点
pNew -> data = val; //将用户输入的数据赋给节点的成员
pTail -> next = pNew; //将最后一个节点的指针指向下一个新的节点
pNew -> next = NULL; //将新节点中的指针置为空
pTail = pNew; //将新节点赋给最后的一个节点
printf("successful!");
}
return pHead; //返回头节点
}
//(2)在链表中插入一个新结点。
//前插法
pNode insertnode_bypre(Node *phead, Node node,int data,int key)
{
Node *pnode = init_node(&node, data);//初始化插入的结点
Node *ptmp = phead;
if (phead == NULL)//链表为空,直接返回初始化的值
{
return pnode;
}
else if (phead->data == key)//处理的第一个结点是否为目标结点
{
phead = pnode;
pnode->next = ptmp;
}
else
{
while((ptmp->next != NULL) && (ptmp->next->data != key))
{
ptmp = ptmp->next;
}
if (ptmp->next == NULL)//没有找到的情况
{
printf("insert key NOT FOUND\n");
}
else//把新结点插入到目标结点的前面
{
ptmp = (Node *)malloc(sizeof(Node)); //分配一个Node类型大小的内存空间,并把分配空间的首地址强制转换成Node *类型的
ptmp->data = data; // 为新结点的数据域赋值
ptmp->next = phead->next; // 将头指针所指向的下一个结点的地址,赋给新创建结点的next
phead->next = ptmp; // 将新创建的结点的地址赋给头指针的下一个结点
}
}
printf("successful!");
return phead;
}
//后插法
pNode insertnode_byback(Node *phead,Node node ,int data,int key)
{
Node *pnode = init_node(&node, data);//初始化插入的结点
Node *ptmp = searchnode(phead,key);//查找目标结点
if (ptmp == NULL)//链表为空,或者没有找到
{
printf("Link is empty or not found key!\n");
return phead;
}
if (ptmp->next == NULL)//如果key为最后一个结点
{
ptmp->next = pnode;
}
else//将新结点插入到目标结点的后面
{
ptmp = (Node *)malloc(sizeof(Node)); //分配一个Node类型大小的内存空间,并把分配空间的首地址强制转换成Node *类型的
ptmp -> next = NULL; // 初始化头结点指向的下一个地址为 NULL
phead -> next = ptmp;
phead = phead->next;
}
printf("successful!");
return phead;
}
// (3)删除链表中的某一个结点。
pNode deletenode(Node *phead, int key)
{
Node *ptmp = phead;
Node *tmp = NULL;
if (phead == NULL)//处理链表为空的情况
{
printf("Link is empty,delete fail!\n");
return NULL;
}
else if(phead->data == key)//单独处理第一个结点
{
phead = phead->next;
free(ptmp); //释放目标结点
ptmp = NULL;
}
else
{
while (ptmp->next != NULL && ptmp->next->data != key)//没找&&没有找到
{
ptmp = ptmp->next;
}
if (ptmp->next == NULL)//没有找到
{
printf("delete key is not found!\n");
return phead;
}
if (ptmp->next->data == key)//找到目标结点并删除
{
tmp = ptmp->next;
ptmp->next = tmp->next;
free(tmp); //释放目标结点
tmp = NULL;
}
}
printf("successful!");
return phead;
}
// (4)在链表中查找某结点并返回其位置。
pNode searchnode(Node *phead,int key)
{
Node *ptmp = phead;
int i = 0;
if (ptmp == NULL) //查找结点,判断该结点是否存在
{
return NULL;
}
while (ptmp->data != key && ptmp->next != NULL)
{
i=i+1;
ptmp = ptmp->next;
}
if (ptmp -> data == key)
{
printf("所在位置为:%d\n",i);
return 0;
}
if (ptmp->next == NULL)
{
printf("该数字不在链表中\n");
return NULL;
}
}
//(5)打印输出链表中的结点元素值。
void traverse_list(pNode pHead)
{
pNode p = pHead->next; //将头节点的指针给予临时节点p
while (NULL != p) //节点p不为空,循环
{
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
//主函数
int main(int argc, int argv[])
{
int opt = 0;
int num = 0;
//创建链表
printf("请创建一个链表:\n");
pNode phead = create_list();
//打印输出链表
printf("打印输出链表:\n");
traverse_list(phead);
//在数字key前边插入数字data
int key;
int data;
Node node;
printf("在数字几前插入:\n");
scanf("%d",&data);
printf("输入你想要插入的数字:\n");
scanf("%d",&key);
insertnode_bypre(phead,node,key,data);
traverse_list(phead);
//在数字key1后边插入数字data1
int key1;
int data1;
Node node1;
printf("在数字几后插入:\n");
scanf("%d",&data1);
printf("输入你想要插入的数字:\n");
scanf("%d",&key1);
insertnode_byback(phead,node,key1,data1);
traverse_list(phead);
//删除节点
int deldata;
printf("删除数字:\n");
scanf("%d",&deldata);
deletenode(phead, deldata);
traverse_list(phead);
//查找数字,输出位置
printf("输入想要查找的数字:\n");
scanf("%d",&num);
searchnode(phead,num);
return 0;
}
以上就是全部内容,如果大家有更好的方法,欢迎大家与我讨论