详解链表的转置问题

来源:互联网 发布:wemall 源码 编辑:程序博客网 时间:2024/05/02 04:16

//题目:                      ------------------链表的转置------------------------
// 要求:
//      将链表的就地转置。就是将链表的数据存储倒置
//例:
//     输入:12345678910
//     输出:10987654321

// 算法分析:
//         程序最主要的地方再于将头接点的后的每个接点都放再头接点的前面。直到头接点到达
//         尾接点。记完成了链表的转置。
// 算法复杂度分析:
//         只是将每个接点前移所以复杂度就链表的长度。O(N);
// 程序分析:
//          程序采用的时C++实现的方式;时用类实现每个接点。程序中用到了可利用空间表,从而加快了
//          程序中要删除接点再生成接点的速度。采用C++的重载new和delete函数。也用到了静态的类成员
//          数据成员用来实现可利用空间表。

#include  <iostream>
using namespace std;
//数据接点的类的实现。
template <class Elem>
class List
{
 private:
  static List<Elem>* freelist;//静态类成员
 public:
  Elem data;
  List* next;
  List(Elem dataval,List* nextval=NULL)//构造函数同时进行类的初始化。
  {
   data=dataval;
   next=nextval;
  }
  List(List* nextval=NULL)
  {
   next=nextval;
  }
  void* operator new(size_t);//new重载函数的声明。
  void operator delete(void*);//delete重载函数的声明。
  ~List(){};
};

template<class Elem>
List<Elem>* List<Elem>::freelist=NULL;// 静态类数据成员的初始化。

// new 重载函数的实现。记得因为是模板函数。所以要记得返回的时候时不指向任何类型的。
// 当你再用到new函数时它就能重新指向你需要的类型。
template <class Elem>
void* List<Elem>::operator new(size_t)
{
 if(freelist==NULL)    //生成一个接点单位的可利用空间表。同样也可以生成多个
  return ::new List;  //如:::new List[n],n是你想生成接点的个数。
 List<Elem>* temp=freelist;
 freelist=freelist->next;
 return temp;
}

template<class Elem>//    delete重载函数的实现。
void List<Elem>::operator delete(void *ptr)
{
 ((List<Elem>*)ptr)->next=freelist;  //因为void* ptr是不指向任何类型的指针。所以要记得强制
 freelist=(List<Elem>*)ptr;           // 转换为List<Elem>*型的指针。
}
//
template<class Elem>
class AList
{
 private:
  List<Elem>* head;  //头指针。
  List<Elem>* tail;  //尾指针。
  List<Elem>* fence; //标记指针。
  int size;          //链表长度。
 public:
  AList()
  {
   head=tail=fence=new List<Elem>; //初始化
   size=0;
  }
  ~AList()
  {
      while(head!=NULL)
   {
    fence=head;
    fence=fence->next;
    delete fence;
   }
  }
  bool append(const Elem&);
  void print() const;
  bool changList();
};
//为了能更好的看到转置的效果我时从尾接点插入数据的。
template<class Elem>
bool AList<Elem>::append(const Elem& T)
{
 if(size==0)          //不设置空的头接点。
 {
  head->data=T;
  tail=head;
  tail->next=NULL;
  ++size;
  return true;
 }
 tail=tail->next=new List<Elem>(T,NULL);
 size++;
 return true;
}
//打印所有数据的函数。这个是不带头接点的打印函数。带头接点的将不同。要从head->next开始。
//而不是从head开始。
template <class Elem>
void AList<Elem>::print() const
{
 List<Elem>* temp=head;
 
  cout<<"<";
  while(temp!=fence)
  {
   cout<<temp->data<<" ";
   temp=temp->next;
  }
  cout<<"|";
  while(temp!=NULL)
  {
   cout<<temp->data<<" ";
   temp=temp->next;
  }
  cout<<">";
}
//这个就是程序转置函数。要转置记得你要三个接点才能实现。
template<class Elem>
bool AList<Elem>::changList()
{
 List<Elem>* temp=head;//temp接点是为了当后面的接点再头接点插入时保证它始终是头接点。
 if(head->next==NULL)//链表为空退出。
  return false;
 while(head->next!=NULL)//当开始的头接点到达尾接点时结束。
 {
  fence=head->next;      //首先将标记接点设置再开始头接点的下一个接点。以保证它始终往后移。
  head->next=fence->next;//删除开始头接点的下一个接点。
  fence->next=temp;    //将删除的接点放到了最前面的接点。 
  temp=fence;    //再将放置头接点的接点做为现在的头接点。
 }
 tail=head;  //开始的头接点变成现在的尾接点了。所以赋给尾接点。
 head=temp;  //再将现在的头接点赋给原来的头接点。实现了所有的有标记的接点回位。
 return true;
}

int main()
{
 AList<char> A;
 char item[100];
 cout<<"  Enter the --10 --char you want to:";
 cin>>item;
 for(int i=0;i<10;i++)
 {
  A.append(item[i]);     //输入数据。
 }
 cout<<"print all element before changing:"<<endl;
 A.print();             //转置前的数据位置。
 A.changList();         //转置
 cout<<"print all element after changed:"<<endl;
 A.print();             //转置后的数据位置。
 return 0;
}
//程序运行结果样例:
//   Enter the ---10---char you want to:houyonghua
//   print all element before changing    
//   <|h o u y o n g h u a >
//   print all element after changed
//   <|a u h g n o y u o h >
//同样程序修改AList<Elem>中的类型也可以进行其他类型的输入和输出。
//            -----------------------------程序实验结束--------------------------------------------------

注:

     这是我学习数据结构时候写的实验习题。其中有很详细的讲解。希望有不懂这个问题的人看了能

知道怎么样去实现链表的转置。