单链表ADT模板简单应用算法设计:单链表的逆置

问题描述 :

目的:使用C++模板设计单链表的抽象数据类型(ADT)。并在此基础上,使用单链表ADT的基本操作,设计并实现单链表的简单算法设计。

内容:(1)请使用模板设计单链表的抽象数据类型。(由于该环境目前仅支持单文件的编译,故将所有内容都集中在一个源文件内。在实际的设计中,推荐将抽象类及对应的派生类分别放在单独的头文件中。参考网盘中的ADT原型文件。)

(2)ADT的简单应用:使用该ADT设计并实现单链表应用场合的一些简单算法设计。

应用:试设计一个算法,将带头结点的单链表A逆置。要求完全利用原表的存储空间,不允许另行定义新链表。

参考函数原型:

template

void Lk_Reverse( LinkList &A ); //测试数据限定为string。实际应用时,不受其限制

输入说明 :

第一行:顺序表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;
}

你可能感兴趣的:(LOG_DHU数据结构,数据结构,c++)