问题描述 :
目的:使用C++模板设计单链表的抽象数据类型(ADT)。并在此基础上,使用单链表ADT的基本操作,设计并实现单链表的简单算法设计。
内容:(1)请使用模板设计单链表的抽象数据类型。(由于该环境目前仅支持单文件的编译,故将所有内容都集中在一个源文件内。在实际的设计中,推荐将抽象类及对应的派生类分别放在单独的头文件中。参考网盘中的ADT原型文件。)
(2)ADT的简单应用:使用该ADT设计并实现单链表应用场合的一些简单算法设计。
应用:试设计一个算法,将带头结点的单链表A逆置。要求完全利用原表的存储空间,不允许另行定义新链表。
参考函数原型:
template
void Lk_Reverse( LinkList
输入说明 :
第一行:顺序表A的数据元素的数据类型标记(0:int,1:double,2:char,3:string)
第二行:单链表A的数据元素(数据元素之间以空格分隔)
输出说明 :
如第一行输入值为0、1、2、3之外的值,直接输出“err”
否则:
第一行:单链表A的遍历结果(数据元素之间以"->"分隔)
空行
第三行:逆置后单链表A的遍历结果(数据元素之间以"->"分隔)
输入范例 :
0
13 5 27 9 32 123 76 98 54 87
输出范例 :
13->5->27->9->32->123->76->98->54->87
87->54->98->76->123->32->9->27->5->13
怎么说呢,虽然这道题很简单但还是一波三折。
我先写了一个在输入数据的同时就输出的题解,然后就可以直接输出链表,直接结束,结果tmd超时了。
不得已,自能写一个逆置函数了,参考了一位网友的一个逆置函数
结果还是tmd超时了(我顿时,地铁,老人,手机),问助教,原来oj在判断’\n‘出了问题,最后ac了(2022.3.29.11:50)
原来是我的判断回车的语句造成超时(2022.3.29.13:00),不是oj的错
于是我又试了一下最初的那个方法,还是超时(如果有哪位大佬帮我看看问题出在哪儿了就万分感谢了)
ok,废话结束,上AC题解
#include
#include
using namespace std;
/* 单链表的结点定义 */
template
struct LinkNode{
T data;
LinkNode* next;
LinkNode(LinkNode* ptr=NULL){
next=ptr;
}
LinkNode(const T& item,LinkNode* ptr=NULL){
next=ptr;
data=item;
}
};
//带头结点和尾指针的单链表
template
class LinkList
{
private:
LinkNode* head;
LinkNode* tail;
public:
LinkList() { head = new LinkNode; tail = head; }
void CreateList_Tail(const T A)//后插法,在链表尾部插入一个节点
{
LinkNode* p = new LinkNode(A);
tail->next = p;
tail = p;
}
void CreateList_Head(const T A)//前插法,没有对尾指针进行设置,在头节点之后插入一个节点
{
LinkNode* p=new LinkNode(A);
LinkNode* temp=head->next;//保存首元节点
head->next=p;
p->next=temp;
}
template
friend void fun(LinkList& a);
template
friend void List_Reverse(LinkList& A);
};
template
void List_Reverse(LinkList& A){
LinkNode *p,*p1,*p2;
p1=A.head->next; //初始化指向首元节点
p=p1->next;//初始化指向第二个节点
p1->next=NULL;//完成逆置后,首元节点将成为尾节点,所以置为NULL
//p2用来指向p的下一个节点
while(p!=NULL){
p2=p->next;
p->next=p1;
p1=p;
p=p2;
}
A.head->next=p1;
}
template
void fun(LinkList& a){
T num;
while(cin>>num)
a.CreateList_Tail(num);
//由于此处输入样例里面结尾没有'\n',所以不用getchar()!='\n'判断循环结束
for (LinkNode* i = a.head->next; i != NULL; i = i->next) i->next != NULL ? (cout << i->data << "->") : (cout << i->data<<"\n");
cout<* i = a.head->next; i != NULL; i = i->next) i->next != NULL ? (cout << i->data << "->") : (cout << i->data);
}
int main()
{
int type;
cin >> type;
if (type == 0) {
LinkList a;
fun(a);
}
else if (type == 1) {
LinkList a;
fun(a);
}
else if (type == 2) {
LinkList a;
fun(a);
}
else if (type == 3) {
LinkList a;
fun(a);
}
else {
cout << "err";
}
return 0;
}
其中List_Reverse函数开始的时候我写的是 :
它是错的,因为在处理尾节点时,p最后并不为NULL,而是指向倒数第二个节点,如果不太清楚建议画图模拟。
//template
//void List_Reverse(LinkList& A){
// LinkNode *p,*p1,*p2;
// p1=A.head->next; //初始化指向首元节点
// p=p1->next;//初始化指向第二个节点
// p2=p->next;//初始化指向第三个节点
// p1->next=NULL;//完成逆置后,首元节点将成为尾节点,所以置为NULL
// //p2用来指向p的下一个节点
// while(p!=NULL){
//
// p->next=p1;
// p1=p;
// p=p2;
// p2=p2->next;
// }
// A.head->next=p1;
//}
此外,在输入数据时:
一开始写的是:
while(cin>>num,a.CreateList_Tail(num),getchar()!='\n');
但输入样例结尾并没有‘\n’,所以会一直超时(这也是我三种方法都超时的原因,助教说是oj判断回车有问题,其实不是,是我函数有问题,感谢*磊的提醒)
后来改成了 :
while(cin>>num)
a.CreateList_Tail(num);
也可以改成:
while(cin>>num,a.CreateList_Tail(num),getchar()==' ';
方法二:
用前插法对链表进行逆置:
template
void List_Reverse(LinkList& A){
LinkNode* p=A.head->next->next;//p初始化指向第二个节点
A.head->next->next=NULL;//逆置完成后首元节点成为尾节点,所以next置为NULL
LinkNode* temp;//temp用来保存p的下一个节点
while(p)
{
temp=p->next;
p->next=A.head->next;
A.head->next=p;
p=temp;
}
}
完整ac代码:
//用前插法来写逆置函数
#include
#include
using namespace std;
/* 单链表的结点定义 */
template
struct LinkNode{
T data;
LinkNode* next;
LinkNode(LinkNode* ptr=NULL){
next=ptr;
}
LinkNode(const T& item,LinkNode* ptr=NULL){
next=ptr;
data=item;
}
};
//带头结点和尾指针的单链表
template
class LinkList
{
private:
LinkNode* head;
LinkNode* tail;
public:
LinkList() { head = new LinkNode; tail = head; }
void CreateList_Tail(const T A)//后插法,在链表尾部插入一个节点
{
LinkNode* p = new LinkNode(A);
tail->next = p;
tail = p;
}
void CreateList_Head(const T A)//前插法,没有对尾指针进行设置,在头节点之后插入一个节点
{
LinkNode* p=new LinkNode(A);
LinkNode* temp=head->next;//保存首元节点
head->next=p;
p->next=temp;
}
template
friend void fun(LinkList& a);
template
friend void List_Reverse(LinkList& A);
};
template
void List_Reverse(LinkList& A){
LinkNode* p=A.head->next->next;//p初始化指向第二个节点
A.head->next->next=NULL;//逆置完成后首元节点成为尾节点,所以next置为NULL
LinkNode* temp;//temp用来保存p的下一个节点
while(p)
{
temp=p->next;
p->next=A.head->next;
A.head->next=p;
p=temp;
}
}
template
void fun(LinkList& a){
T num;
while(cin>>num)
a.CreateList_Tail(num);
for (LinkNode* i = a.head->next; i != NULL; i = i->next) i->next != NULL ? (cout << i->data << "->") : (cout << i->data<<"\n");
cout<* i = a.head->next; i != NULL; i = i->next) i->next != NULL ? (cout << i->data << "->") : (cout << i->data);
}
int main()
{
int type;
cin >> type;
if (type == 0) {
LinkList a;
fun(a);
}
else if (type == 1) {
LinkList a;
fun(a);
}
else if (type == 2) {
LinkList a;
fun(a);
}
else if (type == 3) {
LinkList a;
fun(a);
}
else {
cout << "err";
}
return 0;
}