非循环链表的C++语言定义
//非循环单链表数据结构C艹类声明
template <typename ElemType>
class LinkList
{
public:
class LinkNode
{
public:
ElemType data;
LinkNode *next;
// NodePointer next;
};
typedef LinkNode * NodePointer;
// 下面可以添加很多链表操作函数
void adverse(); //非循环单链表的逆置
void randLinkList(); //产生随机链表
void display(ostream& out) const;
//************************下列为系统自动调用的构造函数和析构函数**************************//
LinkList();
virtual~LinkList();
LinkList(const LinkList<ElemType>& otherL);
protected:
NodePointer head;
};
//非循环单链表的逆置
template <typename ElemType>
void LinkList<ElemType>::adverse()
{
NodePointer r,p,q;
if(!head)
return;
r=NULL,p=head,q=p->next;
while(p)
{
p->next=r;
r=p;
p=q;
if(q)
q=q->next;
}
head=r;
}
//随机产生非循环单链表
void LinkList<ElemType>::randLinkList()
{
clear();
int i,n;
int elem[11];
NodePointer p=head;
NodePointer s;
srand((unsigned)time(NULL));
n=rand()%10+1;
cout<<"用如下随机数生成非循环单链表:"<<endl;
for( i=0;i<=n;i++)
{
elem[i]=rand()%100+1;
cout<<elem[i]<<" ";
}
cout<<endl;
cout<<endl<<"随机生成的非循环单链表为:"<<endl;
for( i=1;i<=n+1;i++)
cout<<"[ "<<i<<"] ";
cout<<endl;
for(i=0;i<=n;i++)
{
s=new LinkNode;
assert(s!=0);
s->data=elem[i];
if(!head)
head=s;
else
p->next=s;
p=s;
if(p)
p->next=NULL;
}
p=head;
while(p)
{
while(p->next!=NULL)
{
cout<<" "<<p->data<<"->";
break;
}
while(p->next==NULL)
{
cout<<" "<<p->data<<"∧";
break;
}
p=p->next;
}
cout<<endl;
}
使用随机产生的数组elem[i]对链表进行初始化的过程如下:
for(i=0;i<=n;i++)
{
s=new LinkNode;
assert(s!=0);
s->data=elem[i];
if(!head)
head=s;
else
p->next=s;
p=s;
if(p)
p->next=NULL;
}
p=head;
看似简单的程序,理解起来对于初学者却很费力,现上传自己的梳理程序流程图如下:
链表的逆置,也体现了指针操作的精髓,其核心思想是:从非循环单链表的第一个结点开始,沿着链表滑动,知道最后一个结点,逐一反转。
具体程序如下:
NodePointer r,p,q;//声明结点指针型的三个指针,分别用来指向当前结点、前结点和后结点
if(!head) //如果当前链表的头指针为空,说明链表不存在,程序终止
return;
r=NULL,p=head,q=p->next; //第一次时,当前指针指向首结点,也就是等于头指针
while(p)
{
p->next=r;//对当前结点的指针赋值,指向前结点,当然首节点反转后成为尾结点,其next指针为NULL
r=p; //r,p,q依次向后滑动
p=q;
if(q)
q=q->next;
}
head=r; 当p=q=NULL时,说明当前结点已经滑动至尾结点之外,此时,只需要将r指针赋值给头指针即可
具体流程图自己在草稿纸上消化如下: