第二次数据结构上机,卡在了模版类的定义…
指针操作比较复杂,调试了很久?
- 熟悉模版类函数的定义方式
- 熟悉链表操作
邻居互换
有一个无头结点的单链表,将相邻两个节点互换位置,返回修改后的链表。
例如
输入1->2->3->4,互换后返回2->1->4->3
不可以通过修改链表节点内的值来实现。
#include<iostream>
using namespace std;
template<class Type>
class List;
template<class Type>
class Linknode{
friend class List<Type>;
public:
Linknode(){next=NULL;}
Linknode(const Type &value){
data=value;
next=NULL;
};
private:
Type data;
Linknode<Type> *next;
};
template<class Type>
class List{
private:
Linknode<Type> *head;
public:
List();//构造函数
~List(){};//析构函数
bool insert(Type element); //尾插入
void show();
void showafter();
bool neighbourexchange();//交换相邻节点
};
//构造函数
template<class Type>
List<Type>::List()
{
head=NULL;
}
template<class Type>
bool List<Type>::insert(Type element){
Linknode<Type>*newnode=new Linknode<Type>(element);
if(newnode==NULL){cerr<<"内存分配错误"<<endl;return false;}
Linknode<Type> *p=head;
if(!p) {head=newnode;return true;}
while(p->next!=NULL)
p=p->next;
p->next=newnode;
return true;
}
template<class Type>
void List<Type>::show(){
Linknode<Type> *p=head;
if(head==NULL) cout<<"此为空链表"<<endl;
else {cout<<"输出链表:"<<endl;
for(;p;p=p->next)
cout<<p->data<<" ";}
cout<<endl;
}
template<class Type>
void List<Type>::showafter(){
Linknode<Type> *p=head;
if(head==NULL) cout<<"此为空链表"<<endl;
else {cout<<"输出邻居互换后链表:"<<endl;
for(;p;p=p->next)
cout<<p->data<<" ";}
cout<<endl;
}
template<class Type>
bool List<Type>::neighbourexchange(){
Linknode<Type> *q=head->next,*p,*r;
if(!q) return false;
head->next=q->next;
q->next=head;
head=q;
if(!head->next->next) return false;
p=q->next;
q=p->next;
while(q->next)
{ r=q->next;
if(r->next==NULL) {
r->next=q;
p->next=r;
q->next=NULL;
return true;
}
q->next=r->next;
r->next=q;
p->next=r;
p=q;
q=p->next;
}
return true;
}
int main()
{ int n,i=0,x;
cout<<"输入链表节点个数:"<<endl;
cin>>n;
cout<<"请输入"<<n<<"个整数"<<endl;
List<int> num;
for(;i<n;i++)
{
cin>>x;
num.insert(x);
}
num.show();
num.neighbourexchange();
num.showafter();
return 0;
}
这题还是比较好写的,写清辅助指针的连接方式和奇数结束情况即可
反转前k个节点
有一个无头结点的单链表,将每k个节点反转顺序,返回修改后的链表。
k是不大于链表长度的正整数,如果链表长度不是k的整数倍,则余下的节点保持顺序不变。
例如
链表1->2->3->4->5
当k=2时,输出2->1->4->3->5
当k=3时,输出3->2->1->4->5
不可以通过修改链表节点内的值来实现。试着使程序仅使用常数级的空间复杂度。
#include<iostream>
using namespace std;
template<class Type>
class List;
template<class Type>
class Linknode{
friend class List<Type>;
public:
Linknode(){next=NULL;}
Linknode(const Type &value){
data=value;
next=NULL;
};
private:
Type data;
Linknode<Type> *next;
};
template<class Type>
class List{
private:
Linknode<Type> *head;
public:
List();//构造函数
~List(){};//析构函数
bool insert(Type element); //尾插入
void show();
void showafter(int k);
int listlength();//链表长度
bool kreverse(int k,int length);//反转每k个结点
};
//构造函数
template<class Type>
List<Type>::List()
{
head=NULL;
}
template<class Type>
bool List<Type>::insert(Type element){
Linknode<Type>*newnode=new Linknode<Type>(element);
if(newnode==NULL){cerr<<"内存分配错误"<<endl;return false;}
Linknode<Type> *p=head;
if(!p) {head=newnode;return true;}
while(p->next!=NULL)
p=p->next;
p->next=newnode;
return true;
}
template<class Type>
void List<Type>::show(){
Linknode<Type> *p=head;
if(head==NULL) cout<<"此为空链表"<<endl;
else {cout<<"输出链表:"<<endl;
for(;p;p=p->next)
cout<<p->data<<" ";}
cout<<endl;
}
template<class Type>
void List<Type>::showafter(int k){
Linknode<Type> *p=head;
if(head==NULL) cout<<"此为空链表"<<endl;
else {cout<<"每"<<k<<"个节点反转后链表:"<<endl;
for(;p;p=p->next)
cout<<p->data<<" ";}
cout<<endl;
}
template<class Type>
int List<Type>::listlength(){
int len=0;
Linknode<Type> *p=head;
for(;p;p=p->next)
len++;
return len;
}
template<class Type>
bool List<Type>::kreverse(int m,int length){
if(m>length) {cout<<"反转节点数超过表长"<<endl<<endl;return true;}
if(m==1) return true;
Linknode<Type> *p=head,*q=p->next,*t=head,*h=head,*pp=head;
if(m==2&&length==2) {head=q;q->next=p;p->next=NULL;return true;}
int i=0,flag=1,headflag=1;
for(i=1;i<m&&h;i++)
h=h->next;//h指向下一组k个节点的起始位置
while(h){
flag=1;
t=h->next;//t储存一组k节点的后继节点
if(headflag==1) {head=h;headflag=0;}
for(i=0;i<m&&h;i++)
h=h->next;
while(q!=t&&q)
{ pp=q->next;
q->next=p;
if(flag==1)
{p->next=h?h:t;flag=0;}
if(p->next==t&&!h)
{ p=q;q=pp;pp=q?q->next:NULL;
while(q!=t)
{q->next=p;p=q;q=pp;pp=q?q->next:NULL;}
return true;}
p=q;q=pp;
}
if(!h)return true;
else {p=t;q=p->next;}
}
}
int main()
{ int n,i=0,x=0,k=0;
cout<<"输入链表节点个数:"<<endl;
cin>>n;
cout<<"请输入"<<n<<"个整数:"<<endl;
List<int> num;
for(;i<n;i++)
{
cin>>x;
num.insert(x);
}
num.show();
cout<<"请输入反转结点数:"<<endl;
cin>>k;
cin.sync();
num.kreverse(k,num.listlength());
num.showafter(k);
return 0;
}
130行代码它来了
模版类链表定义照抄前一题,主要复杂在反转节点函数的写法
思路:
简单情况单独考虑(k=1/只有两个节点)
h记录下一组k个节点的起始位置(h为NULL则是最后一组反转,便于连接下一组k个节点的头指针)
t保留一组k个节点的后继节点(便于处理之后链表长度不够需要返回的情况)
工作指针p,q,pp依次向后轮转反向连接
注意要先判断head的指向(可以直接判别)
最重要的是处理防止访问空指针的问题:时刻注意判断NULL
还有最后一步操作的分类讨论,调试了好久…
写链表还是把思路理清楚,考虑到所有情况再写