目录
一.查找元素:
此段代码仅实现查找元素的功能。
代码部分:
核心代码:
node* lookst(node* head, int x)
{
node* temp = head;//temp是查询专用的指针,temp独立地指向某个结点
while (temp->next != NULL && temp->next->data != x)
temp = temp->next;
/*
循环终止条件有两个:
1.链表循环完毕:即temp->next==NULL,此时不执行temp=temp->next;
2.找到了x:即temp->next->data=x;此时不执行temp=temp->next;
*/
return temp;
//如果查询到了,查询指针指向本结点的前一个结点
//如果没有查询到,查询指针指向链表尾结点
//所以判断是否查询到的方法就是:
//看看查询指针所指向的结点后面还有没有结点
}
完整代码:
//代码仅实现查询功能
#include <iostream>
using namespace std;
struct node
{
int data;
node* next;
};
node* lookst(node* head, int x)
{
node* temp = head;//temp是查询专用的指针,temp独立地指向某个结点
while (temp->next != NULL && temp->next->data != x)
temp = temp->next;
/*
循环终止条件有两个:
1.链表循环完毕:即temp->next==NULL,此时不执行temp=temp->next;
2.找到了x:即temp->next->data=x;此时不执行temp=temp->next;
*/
return temp;
//如果查询到了,查询指针指向本结点的前一个结点
//如果没有查询到,查询指针指向链表尾结点
//所以判断是否查询到的方法就是:
//看看查询指针所指向的结点后面还有没有结点
}
void outlook(node* head, int x)
{
if (head->data == x)//先判断链表首结点是不是要找的数据
cout << "found" << endl;
else
{
node* temp = lookst(head, x);//重新使用查询指针
//依照上面的注释讲解,看看判断方法就是看看查询指针
//所指向的结点后面是否还有结点.如果有,证明查询到了;
//如果没有,证明没有查询到.
if (temp->next==NULL)//如果查询指针所指结点后面没有结点了
cout << "non_found" << endl;//没查询到
else//如果查询指针后面还有结点
{
cout << "found" << endl;//查询到了
}
}
}
int main()
{
int x;
cin >> x;
node* head, * front, * back;
head = NULL;
front = NULL;
while (x != 0)
{
back = (node*)malloc(sizeof(node));
if (back == NULL)
{
cout << "error" << endl;
exit(1);
}
back->data = x;
back->next = NULL;
if (head == NULL)
head = back;
else
front->next = back;
front = back;
cin >> x;
}
int input;
cout << "请输入您要查找的数据" << endl;
cin >> input;
outlook(head, input);//执行函数
//释放堆区内存空间
back = head;
while (back != NULL)
{
front = back;
back = back->next;
free(front);
}
return 0;
}
运行结果1:
运行结果2:
运行结果3:
运行结果4:
按照这个思想, 代码也可以实现将两个子函数合并为一个:
//代码仅实现查询功能
#include <iostream>
using namespace std;
struct node
{
int data;
node* next;
};
void lookst(node* head, int x)
{
node* temp = head;//temp是查询专用的指针,temp独立地指向某个结点
if (temp->data == x)
cout << "found" << endl;
else
{
while (temp->next != NULL && temp->next->data != x)
temp = temp->next;
if (temp->next == NULL)
cout << "non_found" << endl;
else
cout << "found" << endl;
}
/*
循环终止条件有两个:
1.链表循环完毕:即temp->next==NULL,此时不执行temp=temp->next;
2.找到了x:即temp->next->data=x;此时不执行temp=temp->next;
*/
//如果查询到了,查询指针指向本结点的前一个结点
//如果没有查询到,查询指针指向链表尾结点
//所以判断是否查询到的方法就是:
//看看查询指针所指向的结点后面还有没有结点
}
/*
void outlook(node* head, int x)
{
if (head->data == x)//先判断链表首结点是不是要找的数据
cout << "found" << endl;
else
{
node* temp = lookst(head, x);//重新使用查询指针
//依照上面的注释讲解,看看判断方法就是看看查询指针
//所指向的结点后面是否还有结点.如果有,证明查询到了;
//如果没有,证明没有查询到.
if (temp->next==NULL)//如果查询指针所指结点后面没有结点了
cout << "non_found" << endl;//没查询到
else//如果查询指针后面还有结点
{
cout << "found" << endl;//查询到了
}
}
}
*/
int main()
{
int x;
cin >> x;
node* head, * front, * back;
head = NULL;
front = NULL;
while (x != 0)
{
back = (node*)malloc(sizeof(node));
if (back == NULL)
{
cout << "error" << endl;
exit(1);
}
back->data = x;
back->next = NULL;
if (head == NULL)
head = back;
else
front->next = back;
front = back;
cin >> x;
}
int input;
cout << "请输入您要查找的数据" << endl;
cin >> input;
lookst(head, input);//执行函数
//释放堆区内存空间
back = head;
while (back != NULL)
{
front = back;
back = back->next;
free(front);
}
return 0;
}
运行结果相同。
二.插入元素
核心思路:
插入过程:
用malloc( )函数申请取得新结点p, 并让该结点的数据 域为 b,即令 p->data=b;p->next=NULL;
● 在链表中寻找包含元素x的前一个结点,设该结点的存 储地址为q;
● 最后将结点p插入到结点q之后。为了实现这一步,只 要改变以下两个结点的指针域内容:
① 使结点p指向包含元素x的结点(即结点q的后件结 点), 即令 p->next = q->next;
② 使结点q的指针域内容改为指向结点p,即令 q->next = p;
在头指针为head的链表中包含元素x的结点之前插入新元素b
代码部分:
核心代码:
void insert(node** head, int x, int b)
//node**head 定义了一个指向头结点的指针.
//考虑到所查询的数据有可能是链表的第一个结点的数据域,
//如果在头结点前插入结点,就必须定义一个指向头结点的指针,方便连接.
{
node* insertp, * beforeinsert;
//insertp是独立于链表指针之外的指向插入结点的指针
//beforeinsert是查询指针,
//独立于链表之外地指向待查询数据所在结点的前一个结点
insertp = (node*)malloc(sizeof(node));
/*
向链表中插入一个结点的几种特殊情况:
1.链表为空head=NULL;
2.链表的第一个结点为x,则应该在第一个结点之前插入
3.链表中未找到x,在链表尾部插入结点
*/
if (insertp == NULL)
{
cout << "error" << endl;
exit(1);
}
insertp->data = b;
insertp->next = NULL;
if (*head == NULL)//情况1 链表为空
{
*head = insertp;
return;
}
if ((*head)->data == x)//情况2 链表的头结点为x
{
insertp->next = *head;
*head = insertp;
return;
}
beforeinsert = lookst(*head, x);//beforeinsert赋值
insertp->next = beforeinsert->next;
//查询指针所指结点的下一个结点要么是待查询数据所在的结点,
//要么根本就不存在下一个结点,即beforeinsert->next=NULL;
//本行代码代表的含义是:
//将查询指针所指结点的指针域赋值给待插入结点的指针域,
//也就实现了断点位置之后的结点和插入结点的连接
beforeinsert->next = insertp;
//实现了断点位置之前的结点和插入结点的连接
return;
}
完整代码:
#include <iostream>
using namespace std;
struct node
{
int data;
node* next;
};
node* lookst(node* head, int x)
{
node* temp = head;//temp是查询专用的指针,temp独立于链表之外地指向某个结点
while (temp->next != NULL && temp->next->data != x)
temp = temp->next;
/*
循环终止条件有两个:
1.链表循环完毕:即temp->next==NULL,此时不执行temp=temp->next;
2.找到了x:即temp->next->data=x;此时不执行temp=temp->next;
*/
return temp;
//如果查询到了,查询指针指向本结点的前一个结点
//如果没有查询到,查询指针指向链表尾结点
//所以判断是否查询到的方法就是:
//看看查询指针所指向的结点后面还有没有结点
}
void outlook(node* head, int x)
{
if (head->data == x)//先判断链表首结点是不是要找的数据
cout << "found" << endl;
else
{
node* temp = lookst(head, x);//重新使用查询指针
//依照上面的注释讲解,看看判断方法就是看看查询指针
//所指向的结点后面是否还有结点.如果有,证明查询到了;
//如果没有,证明没有查询到.
if (temp->next==NULL)//如果查询指针所指结点后面没有结点了
cout << "non_found" << endl;//没查询到
else//如果查询指针后面还有结点
{
cout << "found" << endl;//查询到了
}
}
}
void insert(node** head, int x, int b)
//node**head 定义了一个指向头结点的指针.
//考虑到所查询的数据有可能是链表的第一个结点的数据域,
//如果在头结点前插入结点,就必须定义一个指向头结点的指针,方便连接.
{
node* insertp, * beforeinsert;
//insertp是独立于链表指针之外的指向插入结点的指针
//beforeinsert是查询指针,
//独立于链表之外地指向待查询数据所在结点的前一个结点
insertp = (node*)malloc(sizeof(node));
/*
向链表中插入一个结点的几种特殊情况:
1.链表为空head=NULL;
2.链表的第一个结点为x,则应该在第一个结点之前插入
3.链表中未找到x,在链表尾部插入结点
*/
if (insertp == NULL)
{
cout << "error" << endl;
exit(1);
}
insertp->data = b;
insertp->next = NULL;
if (*head == NULL)//情况1 链表为空
{
*head = insertp;
return;
}
if ((*head)->data == x)//情况2 链表的头结点为x
{
insertp->next = *head;
*head = insertp;
return;
}
beforeinsert = lookst(*head, x);//beforeinsert赋值
insertp->next = beforeinsert->next;
//查询指针所指结点的下一个结点要么是待查询数据所在的结点,
//要么根本就不存在下一个结点,即beforeinsert->next=NULL;
//本行代码代表的含义是:
//将查询指针所指结点的指针域赋值给待插入结点的指针域,
//也就实现了断点位置之后的结点和插入结点的连接
beforeinsert->next = insertp;
//实现了断点位置之前的结点和插入结点的连接
return;
}
void print(node* head)
{
while (head != NULL)
{
cout << head->data << " ";
head = head->next;
}
cout << endl;
}
void freedom(node*head)
{
node* front, * back=NULL;
back = head;
while (back != NULL)
{
front = back;
back = back->next;
free(front);
}
}
int main()
{
int x;
cin >> x;
node* head, * front, * back;
head = NULL;
front = NULL;
while (x != 0)
{
back = (node*)malloc(sizeof(node));
if (back == NULL)
{
cout << "error" << endl;
exit(1);
}
back->data = x;
back->next = NULL;
if (head == NULL)
head = back;
else
front->next = back;
front = back;
cin >> x;
}
int lookingfor;
cout << "请输入您要查找的数据:" << endl;
cin >> lookingfor;
outlook(head, lookingfor);//执行函数
int ins;
cout << "请输入您要插入的数据:" << endl;
cin >> ins;
insert(&head, lookingfor, ins);
cout << "输出插入后的结果为:" << endl;
node* tempprint = head;
print(tempprint);//打印链表
tempprint = head;
//释放堆区内存空间
freedom(head);
return 0;
}
运行结果1:
运行结果2:
运行结果3:
运行结果4:
三.删除元素
核心思路:
删除过程:
● 在链表中寻找包含元素x的前一个结点,设该结点地址为q。
则包含元素x的结点地址 p=q->next;
● 将结点q后的结点p从链表中删除,
即让结点q的指针指向 包含元素x的结点p的指针指向的结点,即令q->next=p->next;
● 将包含元素x的结点p释放。
代码部分:
核心代码:
void throwout(node** head, int x)
{
node* throwp, * beforethrow;
//throwp是独立的指向待删除结点的指针
//beforethrow是查询指针,独立地指向待查询数据所在结点的前一个结点
/*
从链表中删除一个结点的几种特殊情况
1.链表为空 head=NULL;
打印链表为空的信息,函数返回终止执行;
2.链表的第一个结点值为x,删除第一个结点;
3.链表中未找到x,打印错误信息,函数返回终止执行;
4.链表中找到x
*/
if (*head == NULL)//链表为空
{
cout << "error::this is an empty list" << endl;//打印错误信息
return;
}
if ((*head)->data == x)//头结点是要删除的,删除头结点
{
throwp = (*head)->next;
free(*head);
*head = throwp;
return;
}
beforethrow = lookst(*head, x);
//如果上述两种情况都不是,找到x所在结点的前一个结点,
//并用一个独立的指针引用它.
if (beforethrow->next == NULL)//如果没找到
{
cout << "error::non_found_code in the list" << endl;//打印错误信息
return;
}
//如果找到了
throwp = beforethrow->next;//前一个结点的指针域赋值给独立指针throwp
//此时throwp这个指针指向要删除的结点,并且被前一个结点连接(但是与后一个结点断开)
beforethrow->next = throwp->next;
//将要删结点后一个结点与要删结点前一个结点相连,
//即将要删除的结点的两端相连
free(throwp);//将要删结点释放
return;
}
完整代码:
#include <iostream>
using namespace std;
struct node
{
int data;
node* next;
};
node* lookst(node* head, int x)
{
node* temp = head;//temp是查询专用的指针,temp独立于链表之外地指向某个结点
while (temp->next != NULL && temp->next->data != x)
temp = temp->next;
/*
循环终止条件有两个:
1.链表循环完毕:即temp->next==NULL,此时不执行temp=temp->next;
2.找到了x:即temp->next->data=x;此时不执行temp=temp->next;
*/
return temp;
//如果查询到了,查询指针指向本结点的前一个结点
//如果没有查询到,查询指针指向链表尾结点
//所以判断是否查询到的方法就是:
//看看查询指针所指向的结点后面还有没有结点
}
void outlook(node* head, int x)
{
if (head->data == x)//先判断链表首结点是不是要找的数据
cout << "found" << endl;
else
{
node* temp = lookst(head, x);//重新使用查询指针
//依照上面的注释讲解,看看判断方法就是看看查询指针
//所指向的结点后面是否还有结点.如果有,证明查询到了;
//如果没有,证明没有查询到.
if (temp->next==NULL)//如果查询指针所指结点后面没有结点了
cout << "non_found" << endl;//没查询到
else//如果查询指针后面还有结点
{
cout << "found" << endl;//查询到了
}
}
}
void insert(node** head, int x, int b)
//node**head 定义了一个指向头结点的指针.
//考虑到所查询的数据有可能是链表的第一个结点的数据域,
//如果在头结点前插入结点,就必须定义一个指向头结点的指针,方便连接.
{
node* insertp, * beforeinsert;
//insertp是独立于链表指针之外的指向插入结点的指针
//beforeinsert是查询指针,
//独立于链表之外地指向待查询数据所在结点的前一个结点
insertp = (node*)malloc(sizeof(node));
/*
向链表中插入一个结点的几种特殊情况:
1.链表为空head=NULL;
2.链表的第一个结点为x,则应该在第一个结点之前插入
3.链表中未找到x,在链表尾部插入结点
*/
if (insertp == NULL)
{
cout << "error" << endl;
exit(1);
}
insertp->data = b;
insertp->next = NULL;
if (*head == NULL)//情况1 链表为空
{
*head = insertp;
return;
}
if ((*head)->data == x)//情况2 链表的头结点为x
{
insertp->next = *head;
*head = insertp;
return;
}
beforeinsert = lookst(*head, x);//beforeinsert赋值
insertp->next = beforeinsert->next;
//查询指针所指结点的下一个结点要么是待查询数据所在的结点,
//要么根本就不存在下一个结点,即beforeinsert->next=NULL;
//本行代码代表的含义是:
//将查询指针所指结点的指针域赋值给待插入结点的指针域,
//也就实现了断点位置之后的结点和插入结点的连接
beforeinsert->next = insertp;
//实现了断点位置之前的结点和插入结点的连接
return;
}
void throwout(node** head, int x)
{
node* throwp, * beforethrow;
//throwp是独立的指向待删除结点的指针
//beforethrow是查询指针,独立地指向待查询数据所在结点的前一个结点
/*
从链表中删除一个结点的几种特殊情况
1.链表为空 head=NULL;
打印链表为空的信息,函数返回终止执行;
2.链表的第一个结点值为x,删除第一个结点;
3.链表中未找到x,打印错误信息,函数返回终止执行;
4.链表中找到x
*/
if (*head == NULL)//链表为空
{
cout << "error::this is an empty list" << endl;//打印错误信息
return;
}
if ((*head)->data == x)//头结点是要删除的,删除头结点
{
throwp = (*head)->next;
free(*head);
*head = throwp;
return;
}
beforethrow = lookst(*head, x);
//如果上述两种情况都不是,找到x所在结点的前一个结点,
//并用一个独立的指针引用它.
if (beforethrow->next == NULL)//如果没找到
{
cout << "error::non_found_code in the list" << endl;//打印错误信息
return;
}
//如果找到了
throwp = beforethrow->next;//前一个结点的指针域赋值给独立指针throwp
//此时throwp这个指针指向要删除的结点,并且被前一个结点连接(但是与后一个结点断开)
beforethrow->next = throwp->next;
//将要删结点后一个结点与要删结点前一个结点相连,
//即将要删除的结点的两端相连
free(throwp);//将要删结点释放
return;
}
void print(node* head)
{
node* temp = head;
while (temp != NULL)
{
cout << temp->data << " ";
temp = temp->next;
}
cout << endl;
}
void freedom(node*head)
{
node* front, * back=NULL;
back = head;
while (back != NULL)
{
front = back;
back = back->next;
free(front);
}
}
int main()
{
int x;
cin >> x;
node* head, * front, * back;
head = NULL;
front = NULL;
while (x != 0)
{
back = (node*)malloc(sizeof(node));
if (back == NULL)
{
cout << "error" << endl;
exit(1);
}
back->data = x;
back->next = NULL;
if (head == NULL)
head = back;
else
front->next = back;
front = back;
cin >> x;
}
int lookingfor;
cout << "请输入您要查找的数据:" << endl;
cin >> lookingfor;
outlook(head, lookingfor);//执行函数
int ins;
cout << "请输入您要插入的数据:" << endl;
cin >> ins;
insert(&head, lookingfor, ins);
cout << "输出插入后的结果为:" << endl;
node* tempprint = head;
print(tempprint);//打印链表
int del;
cout << "请输入您要删除的数据:" << endl;
cin >> del;
throwout(&head, del);
cout << "输出删除后的结果为:" << endl;
tempprint = head;
print(tempprint);//打印链表
tempprint = head;
//释放堆区内存空间
freedom(head);
return 0;
}
运行结果1:头结点处的检验
运行结果2:
运行结果3:中间位置的检验
运行结果4:尾结点的检验:
运行结果5:查询不到要删除的数据: