链表的常见操作

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

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

 一、链表创建

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

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

  代码如下:

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

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

代码如下:

判断链表是否有环 

/*判断链表是否有环(循环链表)*/
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;
}


五、合并有序单链表

  问题描述:合并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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值