文中引用了一个单链表就地逆序的算法,在下资质愚钝想了半天没想出来,感谢这位仁兄的分享
点击打开链接
#include<cstdio>
#include<algorithm>
#include<stack>
#include<iostream>
#include<malloc.h>
using namespace std;
typedef struct LNode
{
int data;
struct LNode *next;
} LinkList;
//注意,单链表头节点不保存数据
void InitList(LinkList *&head)//初始化单链表
{
head=(LinkList*)malloc(sizeof(LinkList));
head->next=NULL;
}
//下面是两种创建单链表的方法
//其中头节点为head融合在创建中,因提前建立,所以下方不使用
void CreateListA(LinkList *&head,int a[],int n)//尾插法,依次将元素放在前一个元素后方
{
LinkList *r,*s;//建立两个指针
/*head=(LinkList*)malloc(sizeof(LinkList));//为头结点分配空间
head->next=NULL;*/
r=head;
for(int i=0; i<n; i++)
{
s=(LinkList*)malloc(sizeof(LinkList));
s->data=a[i];
r->next=s;
r=s;//是r不断更新为所插入的下一个元素,再次进入循环
}//通过for循环实现尾插法
r->next=NULL;
}
void CreateListB(LinkList *&head,int a[],int n)//头插法,逻辑顺序与物理顺序相反
{
LinkList *s;
/*head=(LinkList*)malloc(sizeof(LinkList));//分配空间
head->next=NULL;*/
s=head;
for(int i=0; i<n; i++)
{
s=(LinkList*)malloc(sizeof(LinkList));
s->data=a[i];
s->next=head->next;
head->next=s;//元素在插入的过程中新元素排在旧元素后面,所以逻辑物理顺序相反
}
}
void DestroyList(LinkList *&head)//销毁单链表
{
LinkList *pre=head,*p=head->next;//创建两个指针,来回使用
while(p!=NULL)
{
free(pre);
pre=p;
p=pre->next;
}//逐一释放空间
free(pre);//释放最后一个
}
bool ListEmpty(LinkList *&head)//判断是否为空表(是否只含有一个头节点,若是,则为空)
{
return (head->next==NULL);//如果为空,则返回值为1
}
int ListLength(LinkList *head)//计算单链表长度
{
int n=0;
LinkList *p=head;
while(p->next!=NULL)
{
n++;
p=p->next;
}
return n;
}
void DisplayList(LinkList *head)//输出线性表各个元素
{
LinkList *p=head->next;//由于头节点不保存数据,所以从下一个开始
while(p!=NULL)
{
cout<<p->data<<' ';
p=p->next;
}
cout<<endl;
}
bool GetElem(LinkList *head,int i,int &e)//求线性表指定位置i的某个元素,将值赋给e,此处先判断,如成功则赋值输出
{
LinkList *p=head;
for(int j=0; j<i&&p!=NULL; j++)
{
p=p->next;
}
if(p==NULL)//判断循环中断的原因,若为p==NULL,则说明超出单链表范围
return false;
else
{
e=p->data;
return true;
}
}
int LocateElem(LinkList *head,int e)//找出哪一个位置的元素与e值相等,若不存在,输出0
{
LinkList *p=head->next;
int i;
for(i=1; p!=NULL&&p->data!=e; i++)
{
p=p->next;
}
if(p==NULL)//判断终止条件
return 0;//代表不存在,遍历完毕
else
return i;
}
/*下面是单链表的插入和删除操作,可以借用if判断来得出插入或删除值。
也可直接调用函数*/
bool ListInsert(LinkList *&head,int i,int e)//插入元素在第i个位置插入元素e
{
LinkList *p=head,*s;
for(int j=0; j<i-1&&p!=NULL; j++)
{
p=p->next;
}
if(p==NULL)
return false;
else
{
s=(LinkList*)malloc(sizeof(LinkList));
s->data=e;
s->next=p->next;
p->next=s;//画图吧,画图好理解
return true;
}
}
bool ListDelete(LinkList *&head,int i,int &e)//删除线性表第i个元素,将删除元素的值赋给e
{
LinkList *p=head,*q;
for(int j=0; j<i-1&&p!=NULL; j++)
{
p=p->next;
}
if(p==NULL)
return false;
else
{
q=p->next;
if(q==NULL)//判断p下一个节点是否为空,若为空则不满足条件
return false;
e=q->data;//将要删除的元素赋给e
p->next=q->next;
free(q);
return true;
}
}
void nixv(LinkList *&head)//就地逆序
{
LinkList *p,*r;//
p=head->next;
head->next=NULL;
while(p!=NULL)
{
r=p->next;
p->next=head->next;
head->next=p;
p=r;//此处关键,建议画图
}
}
//以下是函数调用测试
int main()
{
LinkList *head;//初定义
InitList(*&head);//头节点
cout<<ListEmpty(*&head)<<endl;
int n;
cout<<"请输入元素个数n"<<endl;
cin>>n;
int m;
int a[100];
for(int i=0; i<n; i++)
{
cin>>a[i];
}
CreateListA(*&head,a,n);//此处为尾插,头插用法与此相同
//个人认为可以用不断插入的方法,这样可以动态分配内存,不用提前开数组依次填入
DisplayList(*&head);//输出测试
cout<<"元素个数为"<<ListLength(head)<<endl;
int e,z;
cout<<"请输入z,e,代表在第z位置插入元素e"<<endl;
cin>>z>>e;
ListInsert(*&head,z,e);//插入测试
DisplayList(*&head);//输出测试
int qq;
cout<<"请输入qq,代表删除第几位置的元素"<<endl;
cin>>qq;
int zz;
ListDelete(*&head,qq,zz);
DisplayList(*&head);//输出测试
cout<<"删除的元素是"<<zz<<endl;
cout<<"逆序输出"<<endl;
nixv(*&head);
DisplayList(*&head);
return 0;
}