链表的常见操作

 

  链表是数据结构的重要内容,在计算机程序中应用广泛,同时也是各公司笔试题目的重点。

  以下简单实现了链表的一些操作,包括创建、增加节点、删除节点、单链表逆置、合并有序链表等。

 

一、链表创建

  链表主要有三种形式,包括单链表、双链表和循环链表。

  单链表每个节点只包含一个后驱指针,双链表节点同时包含一个前驱指针和一个后驱指针,循环链表的尾节点的后驱指向头节点。

  代码如下:

 

/*单链表节点结构*/
typedef
struct NodeType
{
char elem;
NodeType
*next;
}Node;


/*双链表节点结构*/
typedef
struct DNodeType
{
char elem;
DNodeType
*next;
DNodeType
*prev;
}DNode;

 

 

 

创建单链表
/*
创建链表
*/
Node
* CreateList(Node *head)
{
if(NULL == head)//分配头节点空间
head=(Node*)malloc(sizeof(Node)),
head
->next=NULL;

Node
*current=head , *temp;
char ch;

while(1)
{
cout
<<"\n input elem:";
cin
>>ch;
if('#' == ch) /*#结束输入*/
break;
temp
=(Node *) malloc ( sizeof(Node) );
temp
->elem=ch;
temp
->next=NULL;
current
->next=temp; /*当前节点的后驱指向新节点*/
current
=temp; /*当前节点为链表尾节点*/

}

return head;
}

 

创建双链表
/*创建双链表*/
DNode
* DoubleList(DNode *head)
{
if(NULL == head)//分配头节点空间
head=(DNode*)malloc(sizeof(DNode)) , head->prev=NULL , head->next=NULL;


DNode
*current=head , *temp;
char ch;

while(1)
{
cout
<<"\n input elem:";
cin
>>ch;
if('#' == ch) /*#结束输入*/
break;
temp
=(DNode *) malloc ( sizeof(DNode) );
temp
->elem=ch;
temp
->next=NULL;
current
->next=temp; /*当前节点的后驱指向新节点*/
temp
->prev=current; /*新节点的前驱指向当前节点*/
current
=temp; /*当前节点为链表尾节点*/

}

return head;
}

 

创建循环链表
/*创建循环链表*/
Node
* CycleList(Node *head)
{
if(NULL == head)/*分配头节点空间*/
head
=(Node*)malloc(sizeof(Node)),head->next=NULL;

Node
*current=head , *temp;
char ch;

while(1)
{
cout
<<"\n input elem:";
cin
>>ch;
if('#' == ch) /*#结束输入*/
break;
temp
=(Node *) malloc ( sizeof(Node) );
temp
->elem=ch;
temp
->next=NULL;
current
->next=temp; /*当前节点的后驱指向新节点*/
current
=temp; /*当前节点为链表尾节点*/

}
current
->next=head; /*尾节点指向头节点*/
return head;
}

 

二、链表操作

  包括单链表的增加节点、删除节点、输出链表等

添加节点
/*插入节点*/

Node
*InsertNode(Node *head , char elem)
{
if( NULL == head || NULL == elem )
return head;

Node
*current=head->next; /*当前节点*/
Node
*prev=head; /*前驱节点*/
Node
*temp; /*过渡节点*/

while(current) /*移动至尾节点*/
{
prev
=current;
current
=current->next;
}

temp
=(Node*) malloc( sizeof(Node) );
temp
->elem=elem;
temp
->next=NULL;
prev
->next=temp; /*尾节点的后驱指向新节点*/

return head;

}

 

删除节点
/*删除节点*/
Node
*DeleteNode(Node *head,char elem)
{
if(NULL == head || NULL == elem)
return head;
if(NULL == head->next)
return head;

Node
*prev,*current;
prev
=head;
current
=head->next;

while(current)
{
if(current->elem == elem) /*匹配节点元素*/
{
prev
->next=current->next; /*前驱节点的后驱指向当前节点的下一个节点*/
free(current);
/*释放当前节点*/
return head;
}
prev
=current;
current
=current->next; /*移动至下一个节点*/
}

return head;

}

 

输出链表
/*
输出链表
*/
void PrintList(Node *head)
{
Node
* current=head->next;
cout
<<"\n List are:";
while(NULL != current)
{
if(NULL != current->elem)
cout
<<setw(5)<<current->elem;
current
=current->next;
}

cout
<<"\n";
}

 

三、单链表逆置

  单链表逆置在各公司的笔试题中比较常见,以下是其中一种实现。
  算法描述:将链表中每一个节点插入到头结点之后。
  
  代码如下:
单链表逆置
/*单链表逆置*/
Node
*ReverseList(Node *head)
{
if(NULL == head)
return head;
if(NULL == head->next)
return head;
if(NULL == head->next->next)
return head;

Node
*curr=head->next; /*当前节点*/
head
->next=NULL;
Node
*temp;

while(curr)
{
temp
=curr->next; /*暂存下一个节点*/
/*把当前节点插入到head节点后*/
curr
->next=head->next;
head
->next=curr;

curr
=temp; /*移动至下一个节点*/
}

return head;

}

 

四、求单链表中间节点

  在笔试题中比较常见,通常题目描述是:给出一个单链表,不知道节点N的值,怎样只遍历一次就可以求出中间节点。
  算法描述:设立两个指针p1,p2,p1每次移动1个节点位置,p2每次移动2个节点位置,当p2移动到尾节点时,p1指向中间节点。
  
  代码如下:

求中间节点
/*求中间节点*/
Node
* MiddleNode(Node *head)
{
if(NULL == head)
return head;
if(NULL == head->next)
return head->next;

Node
*p1,*p2;
p1
=head;
p2
=head;

while(p2->next)
{
/*p2节点移动2个节点位置*/
p2
=p2->next;
if(p2->next) /*判断p2后驱节点是否存在,存在则再移动一次*/
p2
=p2->next;
/*p1节点移动1个节点位置*/
p1
=p1->next;

}
return p1;

}

 

五、合并有序单链表

  问题描述:合并2个有序单链表,合并后的链表也是排好序的。
  算法描述:对链表A中的每一个节点元素,查找其在链表B中的插入位置,并在B中插入该元素。
  代码如下:
合并有序单链表
/*合并有序单链表*/
Node
* MergeList(Node * h1,Node * h2)
{
if(NULL == h1 || NULL == h2)
return h1;
if(NULL == h1->next )
return h2;
if(NULL == h2->next)
return h1;


Node
* curr1,*curr2,*prev1,*temp;
prev1
=h1; /*链表1的前驱节点*/
curr1
=h1->next; /*链表1的当前节点*/
curr2
=h2->next; /*链表2的当前节点*/
temp
=h2;
while(curr2)
{
while(curr1 && curr1->elem < curr2->elem)/*链表1指针移动至大或等于链表2当前元素的位置*/
prev1
=curr1,curr1=curr1->next;


/*在链表1中插入链表2的当前元素*/
temp
=curr2->next;/*暂存链表2的下一个节点*/
prev1
->next=curr2;
curr2
->next=curr1;

/*链表1移动至新节点*/
curr1
=curr2;
/*链表2移动至下一个节点*/
curr2
=temp;
}

return h1;


}

 

六、判断链表是否有环

  判断链表是否有环即是判断链表是否为循环链表,算法较为简单,一次遍历判断尾指针是否指向头指针即可。

  代码如下:

 

判断链表是否有环
/*判断链表是否有环(循环链表)*/
bool IsCycleList(Node *head)
{
if(NULL== head)
return false;
if(NULL == head->next)
return false;
Node
*current=head->next;
while(current)
{
if(head == current->next)
return true;
current
=current->next;
}
return false;
}

 


 

七、总结
  以上实现了链表的一些常见操作,源文件LinkList.cpp全部代码如下: 
LinkList.cpp

/*
* 作者: 达闻东
* 修改日期: 2010-04-28 17:10
* 描述: 实现链表的常见操作
*
*/
#include
<iostream>
#include
<iomanip>
using namespace std;

/*单链表节点结构*/
typedef
struct NodeType
{
char elem;
NodeType
*next;
}Node;


/*双链表节点结构*/
typedef
struct DNodeType
{
char elem;
DNodeType
*next;
DNodeType
*prev;
}DNode;


/*=============================================================================*/
/*
创建链表
*/
Node
* CreateList(Node *head)
{
if(NULL == head)//分配头节点空间
head=(Node*)malloc(sizeof(Node)),
head
->next=NULL;

Node
*current=head , *temp;
char ch;

while(1)
{
cout
<<"\n input elem:";
cin
>>ch;
if('#' == ch) /*#结束输入*/
break;
temp
=(Node *) malloc ( sizeof(Node) );
temp
->elem=ch;
temp
->next=NULL;
current
->next=temp; /*当前节点的后驱指向新节点*/
current
=temp; /*当前节点为链表尾节点*/

}

return head;
}
/*=============================================================================*/
/*
输出链表
*/
void PrintList(Node *head)
{
Node
* current=head->next;
cout
<<"\n List are:";
while(NULL != current)
{
if(NULL != current->elem)
cout
<<setw(5)<<current->elem;
current
=current->next;
}

cout
<<"\n";
}


/*=============================================================================*/


/*插入节点*/

Node
*InsertNode(Node *head , char elem)
{
if( NULL == head || NULL == elem )
return head;

Node
*current=head->next; /*当前节点*/
Node
*prev=head; /*前驱节点*/
Node
*temp; /*过渡节点*/

while(current) /*移动至尾节点*/
{
prev
=current;
current
=current->next;
}

temp
=(Node*) malloc( sizeof(Node) );
temp
->elem=elem;
temp
->next=NULL;
prev
->next=temp; /*尾节点的后驱指向新节点*/

return head;

}


/*=============================================================================*/

/*删除节点*/
Node
*DeleteNode(Node *head,char elem)
{
if(NULL == head || NULL == elem)
return head;
if(NULL == head->next)
return head;

Node
*prev,*current;
prev
=head;
current
=head->next;

while(current)
{
if(current->elem == elem) /*匹配节点元素*/
{
prev
->next=current->next; /*前驱节点的后驱指向当前节点的下一个节点*/
free(current);
/*释放当前节点*/
return head;
}
prev
=current;
current
=current->next; /*移动至下一个节点*/
}

return head;

}

/*=============================================================================*/


/*单链表逆置*/
Node
*ReverseList(Node *head)
{
if(NULL == head)
return head;
if(NULL == head->next)
return head;
if(NULL == head->next->next)
return head;

Node
*curr=head->next; /*当前节点*/
head
->next=NULL;
Node
*temp;

while(curr)
{
temp
=curr->next; /*暂存下一个节点*/
/*把当前节点插入到head节点后*/
curr
->next=head->next;
head
->next=curr;

curr
=temp; /*移动至下一个节点*/
}

return head;

}

/*=============================================================================*/


/*求中间节点*/
Node
* MiddleNode(Node *head)
{
if(NULL == head)
return head;
if(NULL == head->next)
return head->next;

Node
*p1,*p2;
p1
=head;
p2
=head;

while(p2->next)
{
/*p2节点移动2个节点位置*/
p2
=p2->next;
if(p2->next) /*判断p2后驱节点是否存在,存在则再移动一次*/
p2
=p2->next;
/*p1节点移动1个节点位置*/
p1
=p1->next;

}
return p1;

}


/*=============================================================================*/

/*合并有序单链表*/
Node
* MergeList(Node * h1,Node * h2)
{
if(NULL == h1 || NULL == h2)
return h1;
if(NULL == h1->next )
return h2;
if(NULL == h2->next)
return h1;


Node
* curr1,*curr2,*prev1,*temp;
prev1
=h1; /*链表1的前驱节点*/
curr1
=h1->next; /*链表1的当前节点*/
curr2
=h2->next; /*链表2的当前节点*/
temp
=h2;
while(curr2)
{
while(curr1 && curr1->elem < curr2->elem)/*链表1指针移动至大或等于链表2当前元素的位置*/
prev1
=curr1,curr1=curr1->next;


/*在链表1中插入链表2的当前元素*/
temp
=curr2->next;/*暂存链表2的下一个节点*/
prev1
->next=curr2;
curr2
->next=curr1;

/*链表1移动至新节点*/
curr1
=curr2;
/*链表2移动至下一个节点*/
curr2
=temp;
}

return h1;


}

/*=============================================================================*/

/*创建双链表*/
DNode
* DoubleList(DNode *head)
{
if(NULL == head)//分配头节点空间
head=(DNode*)malloc(sizeof(DNode)) , head->prev=NULL , head->next=NULL;


DNode
*current=head , *temp;
char ch;

while(1)
{
cout
<<"\n input elem:";
cin
>>ch;
if('#' == ch) /*#结束输入*/
break;
temp
=(DNode *) malloc ( sizeof(DNode) );
temp
->elem=ch;
temp
->next=NULL;
current
->next=temp; /*当前节点的后驱指向新节点*/
temp
->prev=current; /*新节点的前驱指向当前节点*/
current
=temp; /*当前节点为链表尾节点*/

}

return head;
}


/*=============================================================================*/
/*输出双链表*/
void PrintDoubleList(DNode *head)
{
if(NULL == head)
return;

DNode
* p;
p
=head;
cout
<<"\n DoubleList are:";
while(p->next)
{
p
=p->next;
if(p->elem)
cout
<<setw(5)<<p->elem;

}

cout
<<"\n DoubleList are:";
while(p->prev)
{
if(p->elem)
cout
<<setw(5)<<p->elem;
p
=p->prev;
}

}


/*=============================================================================*/
/*创建循环链表*/
Node
* CycleList(Node *head)
{
if(NULL == head)/*分配头节点空间*/
head
=(Node*)malloc(sizeof(Node)),head->next=NULL;

Node
*current=head , *temp;
char ch;

while(1)
{
cout
<<"\n input elem:";
cin
>>ch;
if('#' == ch) /*#结束输入*/
break;
temp
=(Node *) malloc ( sizeof(Node) );
temp
->elem=ch;
temp
->next=NULL;
current
->next=temp; /*当前节点的后驱指向新节点*/
current
=temp; /*当前节点为链表尾节点*/

}
current
->next=head; /*尾节点指向头节点*/
return head;
}
/*=============================================================================*/

/*判断链表是否有环(循环链表)*/
bool IsCycleList(Node *head)
{
if(NULL== head)
return false;
if(NULL == head->next)
return false;
Node
*current=head->next;
while(current)
{
if(head == current->next)
return true;
current
=current->next;
}
return false;
}
int main()
{
Node
* head,*p;
Node
* head2,*head3;
DNode
* dHead;
char ch;
head
= NULL;
head2
=NULL;
head3
=NULL;
dHead
=NULL;


//head=(Node*) malloc ( sizeof( Node) );
//head->next = NULL;


//创建单链表
head=CreateList(head);
PrintList(head);


head2
=CreateList(head2);
PrintList(head2);

//插入节点

cout
<<"\n input elem to insert:";
cin
>>ch;
InsertNode(head,ch);
PrintList(head);


//删除节点

cout
<<"\n input elem to delete:";
cin
>>ch;
DeleteNode(head,ch);
PrintList(head);

//单链表逆置

head
=ReverseList(head);
cout
<<"\n Reversed !";
PrintList(head);

//求中间节点

p
=MiddleNode(head);
cout
<<"\n Middle Node is:";
cout
<<p->elem<<endl;

//合并有序单链表

MergeList(head,head2);
cout
<<"\n Merged!";
PrintList(head);

//创建双链表

dHead
=DoubleList(dHead);
PrintDoubleList(dHead);

/*创建循环链表并判断是否有环*/
head3
=CycleList(head3);
cout
<<IsCycleList(head3);
return 0;
}

 

posted @ 2010-04-28 17:15  达闻东  阅读(7241)  评论(5编辑  收藏  举报