2012年(158)
分类: C/C++
2012-11-19 10:39:33
在水精灵的blog上看到趋势的一道考题"线性链表的倒序排列",如果是双向链表就太简单了不值得一提,难就难在"怎样将单链表倒序排列",这道题很常见,我当初也思考过,得出的结论是"更改单链表节点的指针方向,而不是调换其数据",完整算法如下:
for(
Node *pre=0,*next; head&&(next=head->next,head->next=pre,next);
pre=head,head=next );
抛砖引玉,看看有没有更好的算法,或更简洁的代码。
完整的测试代码如下:
#include
#include
using namespace
std;
struct Node
{
int value;
Node* next;
Node(
int v ) : value(v),next(0) {}
};
Node* head = 0;
void Pout( void
)
{
for( Node* p=head; p; p=p->next )
cout <<
p->value << ',';
cout << "END"<<
endl;
}
void Reverse( void )
{
// 等同于for( Node *pre=0,*next;
head&&(next=head->next,head->next=pre,next); pre=head,head=next
)
for( register Node *phead=head,*pre=0,*next; head;
)
{
next = phead->next;
phead->next =
pre;
if( !next )
{
head =
phead;
break;
}
pre =
phead;
phead = next;
}
}
int main( void
)
{
head = 0;
head = new Node(1);
head->next = new
Node(2);
head->next->next = new
Node(3);
Pout();
Reverse();
Pout();
//
内存释放与本主题无关
system("PAUSE");
return
0;
}
------------ 2006-06-21日更新 ------------
#include
using namespace std;
struct Node
{
int value;
Node* next;
Node( int v, Node* p ) : value(v), next(p) {}
};
void reverse( Node*& p )
{
Node* t = 0;
for( ; p ;
)
{
Node* _t = t;
t = p;
p =
p->next;
t->next = _t;
}
p = t;
}
ostream& operator<<( ostream& os, const Node* p )
{
os << '[';
if( p ) { os << p->value; p=p->next;
}
for( ; p; p=p->next ) os << ',' << p->value;
os << ']';
return os;
}
int main(void)
{
Node* p = new Node( 0, new Node( 1, new Node( 2,
new Node( 3, new Node( 4, new Node( 5, 0 ) ) ) ) ) );
cout << p << endl;
reverse( p );
cout <<
p << endl;
return 0;
}
输出:
[0,1,2,3,4,5]
[5,4,3,2,1,0]
网友评论2012-11-19 10:43:03
周星星
“这种成型的算法早已出现在各种教科书上,作coder的应该都学过吧?没学过的就要补补课了。”
------ 批评的好,我确实不知道这是常用的算法,俺是学生物学的,半路出家,没有系统的学习过算法,看来这篇文章真是怡笑大方了,这暴露出我一个缺点:动手能力强,但不爱看书,导致知识面狭窄。工作中也是这样,对于大家都没碰到过的问题我能第一个去解决掉,但是对于已有的知识,其它人就掌握得比我快,因为他们会去问会去看,而我只会埋头摸索。
我买了一个科达相机,但照出来的效果总是不好,所以我一直在琢磨它,但还是用不好,我一个同事看不下去了,劝我说:“求求你,你还是去看看说明书吧!”,哈哈,看来我该改改这个毛病了。我现在用6个字来评价自己,“有智慧,没知识” ^_^
网友评论2012-11-19 10:42:47
一笑
道不同不相与为谋!^_^
1. 编译器是由人设计的,编译器的智慧体现的依然是人的智慧。所以,编译器智慧的提高依赖于人的智慧的提高。
2. 程序员不能依赖于特定编译器,这个世界上除了vs,除了gcc还有很多编译器要使用。如我工作中使用的CR32C这C编译器就很粗糙,他认的//和/**/这种注释,但是如果一行中既有//又有/**/它就不认识了。
3. 社会的发展体现在分工的细化。做MIS开发的coder可以把精力集中在业务逻辑,而把代码优化的工作交给编译器;做编译器开发的coder就能把这个代码优化的工作交给谁?其实,所有作底层的,做软偏硬的coder都要考虑到代码的细节。这并不是谁对谁错的问题,这是社会对我们的分工,这是我们自己选择的路。所以,把自己的意识强加给别人是不对的;看待别人的观点,也要批判的看,设身处地的看。
4. 星星刚贴出这篇文章时我就看到了,但是我没有回复。因为,这种成型的算法早已出现在各种教科书上,作coder的应该都学过
网友评论2012-11-19 10:42:32
周星星
^_^ 有些编译器笨了些,因此我修改了一下代码,以保证所有编译器都能优化它,修改点:
a. 临时变量使用了register修饰,这是不必要的,但我依然写出来,这不是给编译器,而是给人看的
b. 将非本地的head赋值到本地,然后在退出时再赋值回去。这一点很必要,好多编译器还不支持这个优化。
for( register Node *phead=head,*pre=0,*next; head; )
{
next = phead->next;
phead->next = pre;
if( !next )
{
head = phead;
break;
}
pre = phead;
phead = next;
}