对这道题目和我的数据结构课程致以最崇高的敬意。
样例输入:
int main() {
LinkedList<int> * list = new LinkedList<int>;
LinkedList<int> * stack = new Stack<int>;
LinkedList<int> * queue = new Queue<int>;
cout << "LinkedList" << endl;
list->pushFront(1);
list->pushBack(2);
list->pushBack(3);
list->pushFront(4);
list->print();
list->popFront();
list->popBack();
list->print();
cout << list->size() << endl;
cout << stack->name() << endl;
stack->push(1);
stack->push(2);
stack->push(3);
stack->push(4);
cout << stack->peak() << endl;
stack->pop();
cout << stack->pop() << endl;
cout << stack->peak() << endl;
cout << queue->name() << endl;
queue->push(1);
queue->push(2);
queue->push(3);
queue->push(4);
cout << queue->peak() << endl;
queue->pop();
cout << queue->pop() << endl;
cout << queue->peak() << endl;
delete list;
delete stack;
delete queue;
return 0;
}
样例输出:
LinkedList
4 1 2 3
1 2
2
Stack
4
3
2
Queue
1
2
3
AC代码:
#include<iostream>
#include<cstdio>
using namespace std;
template <class T>
class LinkedList{
private:
struct Node{
T data;
Node *next, *prev;
Node(const T &x){
data = x;
next = NULL;
prev = NULL;
}
};
protected:
Node *head;
Node *tail;
int length;
void clear(){
Node *p = head, *q;
while(p){
q = p->next;
delete p;
p = q;
}
length = 0;
head = NULL;
tail = NULL;
}
public:
LinkedList(){
head = NULL;
tail = NULL;
length = 0;
}
void pushFront(T k){
Node *tmp = new Node(k);
tmp->next = head;
if(head) head->prev = tmp;
head = tmp;
if(!tail) tail = head;
length++;
}
void pushBack(T k){
Node *tmp = new Node(k);
tmp->prev = tail;
if(tail) tail->next = tmp;
tail = tmp;
if(!head) head = tail;
length++;
}
T popFront(){
if(head){
if(head==tail) tail = NULL;
Node *tmp = head;
head = head->next ;
if(head) head->prev = NULL;
length--;
T x = tmp->data ;
delete tmp;
return x;
}
else return T();
}
T popBack(){
if(tail){
if(head==tail) head = NULL;
Node *tmp = tail;
tail = tail->prev;
if(tail) tail->next = NULL;
length--;
T x = tmp->data;
delete tmp;
return x;
}
else return T();
}
int size(){
return length;
}
LinkedList(const LinkedList &x){
Node *q = x.head;
while(q){
pushBack(q->data);
q = q->next ;
}
length = x.length;
}
void print(){
Node *q = head;
while(q){
cout<<q->data <<" ";
q = q->next;
}
cout<<endl;
}
virtual ~LinkedList(){
clear();
}
virtual const char *name(){
return (char *)("LinkedList");
}
virtual T peak(){
return head->data;
}
virtual T pop() {
return popFront();
}
virtual void push(T val){
pushFront(val);
}
};
template <class T>
class Stack:public LinkedList<T>{
public:
const char *name(){
return (char *)("Stack");
}
T peak(){
return this->head->data;
}
T pop(){
return LinkedList<T>::popFront();
}
void push(T k){
LinkedList<T>::pushFront(k);
return;
}
~Stack(){
LinkedList<T>::clear();
}
};
template <class T>
class Queue:public LinkedList<T>{
public:
const char *name(){
return (char *)("Queue");
}
T peak(){
return LinkedList<T>::head->data;
}
T pop(){
return LinkedList<T>::popFront();
}
void push(T k){
LinkedList<T>::pushBack(k);
return;
}
~Queue(){
LinkedList<T>::clear();
}
};
本题反思: 1、类模板的写法!哪里加template ?哪里加T ? 2、Node采用内嵌类的写法,成为LinkedList的private部分,内嵌类可以被继承,private继承的内嵌类自然无法访问,但protected和public是可以被继承的,在使用Node *p定义一个指针p的时候,要在前面加关键字typename (详情请见后续附上的实验) 3、Node类型的变量和指针其实没有必要被子类使用,因为可以在基类里面写好函数,子类直接调用就可以了(如clear()) 4、Clear()写的时候要注意!!!不可以用已经被delete掉的变量再来->next,因为根本无法这样做啊啊啊!思路要清晰!遍历可以就一个指针不停往后跑因为没有删除操作,但是clear和pop必须定义两个指针,为了保证你删完了还找得到后续的结点,否则删完了就是删完了,后面也找不到了 5、注意子类调用析构函数结束后,是会调用父类的析构函数的!所以你在写clear的时候一定要把head和tail置为0,否则第二次析构的时候会再次析构一遍,导致RE!!(应该是RE吗) 6、注意popFront() 和popBack() !弹出结点的时候注意,只剩一个结点时的情况比其他更复杂一些!如果按照之前的操作,删头只改头,删尾只改尾,会导致删完头了tail还在,删完尾了head还在,导致“链删完后再压入,本该回到初始状态(head,tail都为0),但实际上却不一样了(有的不为0)”(如果你用length判断该链表是否为空,也许会更不容易出错一些,但是引入一个length进入考虑会增加思考的复杂程度(其实也不会))总之,再clear就完完全全地清空好了!回到原先的初始状态一模一样总不会出错 7、注意tail的维护!!!!特别是删了尾巴以后要加if(tail) tail->next=NULL; 否则next还指着一个地址,输出的时候就会出错! 8、结构体指针要用-> ,不可以用. !!! 9、虚函数!在父类里面必须实现啊!!(如果你根本没定义该父类或子类的对象,另当别论,因为它根本没实例化,自然不需要涉及这些语句)纯虚函数不需要实现。 10、类模板作为基类:注意二段式查找相关的理论!类模板作为基类,在实例化之前,它的子类并不知道自己继承了什么,所以会把父类的内部成员看作非成员,所以会显示你使用的东西没有被定义。解决方法是:使用指针this->f(); 或指明A<T>::f(); 根据资料,还可以写using A<T>::f(); 记得带上模板<T> 11、提交前还是检查下哈……该删的要删!免得罚时太多还搞得心里不停自我怀疑…… 12、该自己造数据就快点造!比较好的习惯是:读题仔细,每一步想清楚,不清楚的写下来不要埋地雷,写下来后动手演示画图演算不要对着屏幕空想,样例过了自己造点数据测试一下,提交前检查也没有多余输出。
其余实验及反思: 1、结构体Node不内嵌:放在外面,也是模板,全是public,使用时需要加上模板参数<T> 2、protected和public内嵌,以及类模板作为基类继承: 实验代码如下,实验结果如上所示
#include<iostream>
#include<cstdio>
using namespace std;
template<class T>
class A{
public:
struct B{
T data;
};
protected:
T x;
};
template <class T>
class C:public A<T>{
A<T>::x;
C:A<T>::x;
typename A<T>::B *p;
};
int main(){
}
|