链表的常见操作

 

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

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

 

一、链表创建

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

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

  代码如下:

 

  
   
   /*
   单链表节点结构
   */
   
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 ;
}

 

    原文作者:达闻东
    原文地址: https://www.cnblogs.com/xnwyd/archive/2010/04/28/1723151.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞