您的位置:首页 > 职场人生

四道有趣的单链表面试题(单链表反序、找出链表的中间元素、链表排序、判断一个单链表是否有环)

2014-03-15 11:54 447 查看
参考:http://blog.sina.com.cn/s/blog_725dd1010100tr4y.html

四道有趣的单链表面试题(单链表反序、找出链表的中间元素、链表排序、判断一个单链表是否有环)

以下给出链表结点的数据结构:

template <class T>

struct LinkNode{   //链表节点
T data;
LinkNode<T>* link;
LinkNode(LinkNode<T>* ptr=NULL){link=ptr;}
LinkNode(const T& x,LinkNode<T>* ptr=NULL){link=ptr;data=x;}

};

以下给出链表的定义(带有附加头结点):

template <class T>

class SList{

private:
LinkNode<T>* first;

public:
SList(){first=new LinkNode<T>;}   //构造函数
SList(T& x){first=new LinkNode<T>(x);} //构造函数
SList(SList<T>& L); //复制构造函数
~SList();  //析构函数
int Length()const; //链表长度
LinkNode<T>* getHead()const{return first;}
void setHead(LinkNode<T>* p){first=p;}
bool Search(T& x);//搜索x元素
LinkNode<T>* Locate(int i)const; //定位
T getData(int i)const;   //取出元素值
void setData(int i,const T& x); //设置元素值
bool Insert(int i,const T& x); //插入
bool Remove(int i); //删除第i个元素
bool isEmpty()const{return first->link==NULL?true:false;}
bool isFull()const{return false;}
void Input(int endTag);
void vInput(int endTag);
void Output()const;
void Reverse();
LinkNode<T>* findMid();
SList<T>& operator=(SList<T>& L);

};
Q1 单链表的反序(cur为链表的第一个元素,next为cur的下一个元素,每次将next移到first后面之后,cur是一直不变的,next移动成功之后,重新设置next=cur->link)

(我将题目的意思理解错了,下面的程序实在头结点不变的情况下,对单链表进行反转,但是实际上应该是头结点变成尾节点,尾节点变成头结点,哎呀,懒得改了)

template <class T>

void SList<T>::Reverse(){
if(first->link==NULL||first->link->link==NULL) {cout<<"不需要倒置"<<endl;return;};
LinkNode<T>* cur=first->link;
LinkNode<T>* next=cur->link;
while(cur->link!=NULL){
cur->link =next->link;
next->link=first->link;
first->link=next;
next=cur->link;
}

}

Q2 找出链表的中间元素

思路分析:

 单链表的一个比较大的特点用一句广告语来说就是“不走回头路”,不能实现随机存取(random access)。如果我们想要找一个数组a的中间元素,直接a[len/2]就可以了,但是链表不行,因为只有a[len/2 - 1] 知道a[len/2]在哪儿,其他人不知道。因此,如果按照数组的做法依样画葫芦,要找到链表的中点,我们需要做两步(1)知道链表有多长(2)从头结点开始顺序遍历到链表长度的一半的位置。这就需要1.5n(n为链表的长度)的时间复杂度了。有没有更好的办法呢?有的。想法很简单:两个人赛跑,如果A的速度是B的两倍的话,当A到终点的时候,B应该刚到中点。这只需要遍历一遍链表就行了,还不用计算链表的长度。

template <class T>

LinkNode<T>* SList<T>::findMid(){
if(first->link==NULL) return first;
LinkNode<T>* slow=first;
LinkNode<T>* fast=first;
while(fast!=NULL&&fast->link!=NULL){
slow=slow->link;
fast=fast->link->link;}
return slow;

}

(上面的程序,如果链表的长度为奇数,显然找到中间元素,如果链表的长度为偶数,找的是中间两个元素之中的第二个元素)

Q3  链表排序(没看懂to be continued)

Q4  判断一个单链表是否有环

思路分析:

   这道题是《C专家编程》中的题了。其实算法也有很多,比如说:我觉得进行对访问过的结点进行标记这个想法也不错,而且在树遍历等场合我们也经常使用。但是在不允许做标记的场合就无法使用了。在种种限制的条件下,就有了上面的这种算法,其实思想很简单:就像两个人在操场上跑步一样,只要有个人的速度比另一个人的速度快一点,他们肯定会有相遇的时候的。不过带环链表与操场又不一样,带环链表的状态是离散的,所以选择走得快的要比走得慢的快多少很重要。比如说这里,如果一个指针一次走三步,一个指针一次走一步的话,很有可能它们虽然在一个环中但是永远遇不到,这要取决于环的大小以及两个指针初始位置相差多少了。

template <class T>

bool isLoop(SList<T>& L){
LinkNode<T>* slow=L.getHead();
LinkNode<T>* fast=L.getHead();
while(fast!=NULL&&fast->link!=NULL){
slow=slow->link;
fast=fast->link->link;
cout<<slow->data<<" "<<fast->data<<endl;
if(slow==fast) return true;
}
return false;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++
相关文章推荐