【题目描述】
用C++语言和类实现单链表,含头结点
属性包括:data数据域、next指针域
操作包括:插入、删除、查找
注意:单链表不是数组,所以位置从1开始对应首结点,头结点不放数据
类定义参考
【输入】
第1行先输入n表示有n个数据,接着输入n个数据
第2行输入要插入的位置和新数据
第3行输入要插入的位置和新数据
第4行输入要删除的位置
第5行输入要删除的位置
第6行输入要查找的位置
第7行输入要查找的位置
【输出】
数据之间用空格隔开,
第1行输出创建后的单链表的数据
每成功执行一次操作(插入或删除),输出执行后的单链表数据
每成功执行一次查找,输出查找到的数据
如果执行操作失败(包括插入、删除、查找等失败),输出字符串error,不必输出单链表
【输入样例】
6 11 22 33 44 55 66
3 777
1 888
1
11
0
5
【输出样例】
11 22 33 44 55 66 \n
11 22 777 33 44 55 66 \n
888 11 22 777 33 44 55 66 \n
11 22 777 33 44 55 66 \n
error\n
error\n
44\n
花了一个多小时,从部分正确到AC
#include<iostream>
using namespace std;
class ListNode {//结点类
public:
int data;//数据域
ListNode* next;//指针域,指向后继
ListNode() {//结点初始化
next = NULL;//将指针置为空
}
};
class LinkList {
public:
ListNode* head;//创建头指针
int len;//链表长度
LinkList();//初始化链表
~LinkList();//析构链表
ListNode* LL_index(int i);//返回第i个结点的指针
int LL_get(int i);//获取第i个数据
int LL_insert(int i, int item);//将item插入到第i个位置
int LL_del(int i);//删除第i个结点
void LL_display();//输出单链表内容
};
LinkList::LinkList() {
head = new ListNode();//创建动态链表,数据类型为ListNode结点类
len = 0;//初始化长度
}
LinkList::~LinkList() {//逐个结点回收的原因见注释。
ListNode * p = head, *q;
while (p != NULL) {//只要头结点不是最后一个数据元素(指向空),就执行
q = p;//q负责记录下一个结点,便于当前p释放后,q及时补充。(定下太子再驾崩)
p = p->next;//如果只用一个p变量,delete后指向下一个,会出现 找不到下一个元素地址 的问题。
delete q;
}
len = 0;
head = NULL;//头结点为空,说明表已经全部清空了。
}
ListNode* LinkList::LL_index(int i) {//返回第i个结点的指针
ListNode* p=head;
int j = 1;
if (i == 0) {//如果是第0个,则对应的是头指针
return head;
}
p = p->next;//为什么不写在前面声明的时候?因为,存在i=0时的头结点情况,如果写在前面,就直接跳过了。
while ((p != NULL) && (j < i)) {//不断向后移
p = p->next;
j++;
}
if ((j > i)||!p) {
cout << "error" << endl;
return 0;
}
else {
return p;
}
}
int LinkList::LL_get(int i) {//获取第i个数据
if ((i <= 0) || (i > len)) {
cout << "error" << endl;
return 0;
}
ListNode* p = head->next;
int j = 1;
while ((p != NULL) && (j < i)) {
p = p->next;
j++;
}
if ((p == NULL) || (i < j)) {
cout << "error" << endl;
return 0;
}
else {
cout << p->data << endl;
return 1;
}
}
int LinkList::LL_insert(int i, int item) {
if (i <= 0 || i > len + 1) {//i输入不合法的情况
cout << "error" << endl;
return 0;
}
ListNode* p = LL_index(i - 1);//找到要插入的前一个结点,因为插入从这一位就要开始改变了!!
if (p == NULL) {//i-1不存在,超出长度等其他原因!!
cout << "error" << endl;
return 0;
}
ListNode* s = new ListNode();//动态创建一个新的结点,代表了要插入的结点
s->data = item;//结点的数据域储存插入的元素
s->next = p->next;//建立要插入的结点的后继
p->next = s;//建立要插入的的结点的前驱
len++;//插入后,长度要加1!!!
return 1;
}
int LinkList::LL_del(int i) {//删除第i个结点
if (i <= 0 || i > len) {//判断i是否合法
cout << "error" << endl;
return 0;
}
ListNode* p = LL_index(i-1);//找到要插入的前一个结点,因为删除从这一位就要开始改变了(后继要改变)
if (p == NULL) {//为空,或者i不合法
cout << "error" << endl;
return 0;
}
ListNode* q = p->next;//q就是要删除的那个结点
if (q != NULL) {//为什么要多加一个这个判断?因为判断了i-1合法,你也无法保证i不是最后一位的下一位(此时不合法)
p->next = q->next;
delete q;
len--;//删除后要记得减1!!!
return 1;
}
else {
cout << "error" << endl;
return 0;
}
}
void LinkList::LL_display() {
ListNode* p = head->next;//从第一个有效的结点开始
while (p) {//只要不是空结点 或者 最后一个结点的下一个
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
int main() {
int len;
cin >> len;
int item;//表示一个个数据域的元素
LinkList mylist;
for (int i = 1; i <= len; i++) {//完成一个个插入
cin >> item;
mylist.LL_insert(i, item);
}
mylist.LL_display();//第一行输出
int times = 2;//插入和删除都要两次
int i;//插入 or 删除位数
while (times--) {
cin >> i >> item;
if (mylist.LL_insert(i, item)) {//为什么不能和输出并列,因为会输出好几行;已经error,就不用输出链表元素了
mylist.LL_display();
}
}
times = 2;//插入和删除都要两次
while (times--) {
cin >> i;
if (mylist.LL_del(i)) {
mylist.LL_display();
}
}
times = 2;//插入和删除都要两次
while (times--) {
cin >> i;
mylist.LL_get(i);
}
return 0;
}