链表的算法总结

1、判断链表是否存在环型链表问题

问题:判断一个链表是否存在环,例如下面这个链表就存在环,n1-->n2-->n3-->n4-->n5-->n2,环的开始结点是n5

方法:

这里有个比较简单的解法:设两个指针p1,p2,每次循环p1向前走一步,p2向前走两步,直到p2碰到NULL指针(无环)或两个指针相等结束循环算法(有环),即如果两个指针相等则说明存在环。

代码如下:

          

/*节点数据结构*/  
struct link{  
    int data;  
    link * next;  
};  
  
/* 
*判断是否有环的方法 
* 
*参数来头节点的指针 
*/  
bool isLoop(link * head){  
    //p1步长为1;p2步长为2   
    link* p1 = head,*p2 = head;  
      
    //如果只有一个节点或两个节点,直接return false   
    if(head == NULL || head->next == NULL){  
        return false;  
    }  
      
    //循环前进,直到p2走到NULL或p2追上p1   
    do{  
        p1 = p1->next;  
        p2 = p2->next->next;  
    }while(p2 && p2->next && p1!=p2);  
  
    //如果有环   
    if(p1 == p2){  
        return true;  
    else  
        return false;  
}  

2、链表反转

问题:链表反转,比如原链表是1-->2-->3-->4-->5 通过反转后成为5-->4-->3-->2-->1

解法一:利用三个指针,当前要反转的节点的指针,当前节点之前的节点指针,当前节点之后的节点指针;反转后再向后继续遍历

代码如下:

 

/*节点数据结构*/  
struct linka{  
    int data;  
    link * next;  
};  
  
/* 
*反转 
* 
*参数:头节点的指针的引用 
*/  
bool reverse(link * &head){  
    //只有一个节点,即不用反转,直接返回   
    if(head == NULL)  
        return;  
  
    //定义3个辅助指针,pre指向当前要反转的节点的前一个节点;cur为当前要反转的节点;ne指向当前反转的节点的下一个节点   
    linka * pre,*cur,*ne;  
    //初始化指针   
    pre = head;  
    cur = head->next;  
    //循环,直到cur为NULL   
    while(cur){  
        ne = cur->next;  
        cur->next = pre;  
        pre = cur;  
        cur = ne;  
    }  
      
    //反转到最后,设置头节点指针   
    head->next = NULL;  
    head = pre;  
}  


解法二:利用递归。这种方法的基本思想是在反转当前节点之前先调用递归函数反转后续节点。不过,这个方法有个缺点:在反转后的最后一个节点会形成一个环,所以必须将函数的返回节点的next设为NULL.因为要改变head指针,所以我用了引用

代码如下:

/*节点数据结构*/  
struct linka{  
    int data;  
    link * next;  
};  
  
/* 
*反转 
* 
*参数:头节点的指针的引用 
*/  
linka * reverse(linka * p,link * &head){  
    if(p == NULL || p->next == NULL){  
        head = p;  
        return p;  
    }else {  
        linka* tmp = reverse(p->next,head);  
        tmp->next = p;  
        return p;     
    }  
}  


3、链表的合并

说明:递增有序的2个单链表合并成一个递增有序的单链表,不用任何库函数调用。

代码如下:

#include <iostream>  
using namespace std;  

#define move_node(a_node)   do{a_node = a_node->next;}while(0)
  
/* 单链表节点 */  
struct node{  
    int value;  
    node* next;  
    node()
    {
    	value = 0;
    	next = NULL;
    }
};  

node* createList(int *l,int s)
{
	node *temp = NULL;  
	if(s > 0)
	{
		node* h = new node();  
		h->value = l[0];
		temp = h;
		node *p;  
		for(int i = 1;i < s;++i)
		{
			p = new node();  
			p->value = l[i];
			h->next = p
			move_node(h);
		}
	}
	return temp;
}
 
/* 遍历输出链表节点 */  
void print(node* head){  
    node* p = head;  
    while ( p != NULL ){  
       cout << p->value << " ";  
       p = p->next;  
    }  
    cout << endl;  
}  
  
/* 两个有序链表进行合并 */  
node* merge(node* head1, node* head2){  
  	if(!head1)return head2;
  	if(!head2)return head1;
  	
    node* head,*record_head; //合并后的头指针   
   
   if (head1->value < head2->value ){  
    record_head = head = head1;  
    move_node(head1);
   }else{  
    record_head = head = head2;  
    move_node(head2);
   }  
		
    while (head1 && head2){  
       if (head1->value < head2->value ){  //如果链表1的值小于链表2的值,链表1的指针向下指
            head->next = head1;
            move_node(head);
            move_node(head1);
       }else if ( p->value == q->value ){//链表1的值等于链表2时,两链表指针都向下指   
             head->next = head1;
             move_node(head);
             head->next = head2;
             move_node(head);
             move_node(head1);
						 move_node(head2);
       }else{//如果链表1的值大于链表2的值,链表2的指针向下指
            head->next = head2;
            move_node(head);
            move_node(head2);
       }  
    }  
  
    if (head1)head->next = head1;
  	else if (head2)head->next = head2;
  		
    return record_head;  
}  
  
int main(){  
    /* 建立有序链表A */  
    int a[5] = {1, 5, 8, 10, 20};  
    node * headA  = createList(a,sizeof(a)/sizeof(a[0]));
      
    print(headA);  
  
    /* 建立有序链表B */  
    int b[3] = {3, 4, 9};  
    node * headB = createList(b,sizeof(b)/sizeof(b[0]));
      
    print(headB);  
  
    node *head = merge(headA, headB);  
    print(head);  
      
    return 0;  
}  






 



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值