链表专题[三种逆置方式和微软笔试题]

说起链表,是大家最熟悉的数据结构了,也是大学上课时比较先讲到的。那么是否真正掌握了呢。

单链表逆置是最常考的题目,但完全写正确好像三种方式也没那么容易吧。

第一种:非递归,思路就是从头结点开始,记录头结点的下一个结点,同时将头结点的指针指向之前的结点(设为NULL),然后将头结点的值赋给之前的结点,然后继续下一个结点的逆置,直到为空。

第二种:  递归方式。思路就是一直递归,直到最后一个结点的之前一个结点结束,这时然后最后一个结点的指针指向之前一个结点,同时将之前一个结点的指针置为空(这样顺便修改了原来链表头结点的指针为空)。难点在于怎么返回逆置之后的头结点。

第三种: 栈。既然可以递归了那么考虑用栈来解决。

好了,貌似单链表比较复杂的操作我们掌握了。问题解决了,那么是否能灵活运用呢?看下面一道题目(微软2014年校招编程题)

Given a singly linked list L: (L0 , L1 , L2...Ln-1 , Ln). Write a program to reorder it so that it becomes(L0 , Ln , L1 , Ln-1 , L2 , Ln-2...).
struct Node  
{  
    int val_;  
    Node* next;  
};  
Notes:
1)Space Complexity should be O(1) 
2)Only the ".next" field of a node is modifiable.

注意:空间复杂度为O(1)意味着不能有大于O(1)的辅助空间。

注意是从尾倒着插,可能会用到逆置,那解题思路是神马呢?

根据长度将链表分为两半,对后面的链表进行逆置,然后将两个链表合并(擦,神一样的思路啊,这就是链表逆置和合并的灵活应用了,当做为笔试题是否能想到呢。。。),好了,废话不多说了,代码在下面,看注释吧。

#include<iostream>
#include<string>
#include<stack>
using namespace std;
struct ListNode{
	int value;
	ListNode* next;
};
//增加元素
void AddToList(ListNode** pHead,int value){
	ListNode* pTemp = *pHead; 
	pTemp = (ListNode *)malloc(sizeof(ListNode));
	pTemp->value = value;
	pTemp->next = NULL;
	if(*pHead == NULL)
		*pHead = pTemp;
	else{
		ListNode* pNTemp = *pHead;
		while(pNTemp->next != NULL)
			pNTemp = pNTemp->next;
		pNTemp->next = pTemp;
	}
}
//求长度
int ListLen(ListNode* pHead){
	int n =0;
	while(pHead != NULL){
		pHead = pHead->next;
		n++;
	}
	return n;
}
//非递归逆置
ListNode* Reverse(ListNode* pHead){
	ListNode* pTemp = pHead;
	ListNode *pre,*plast = NULL;
	while(pTemp!= NULL){
		pre = pTemp->next;
	    pTemp->next = plast;
		plast = pTemp;
		pTemp = pre;
	}
	return plast;
}
//递归逆置,关键是如何在递归中找到起点(原来的最后一点)
ListNode* Reverse_recurve(ListNode* pHead){
	if(pHead == NULL || pHead->next == NULL )
		return pHead;
	ListNode *pHead1 = Reverse_recurve(pHead->next);
	pHead->next->next = pHead;		
	pHead->next = NULL;
	return pHead1;
}
//用栈逆置
ListNode* Reverse_stack(ListNode* pHead){
	stack<ListNode*> lstack;
	while(pHead != NULL){
		lstack.push(pHead);
		pHead = pHead->next;
	}
	pHead = lstack.top();
	ListNode* plast = pHead;
	ListNode* pre;
	lstack.pop();
	while(!lstack.empty()){
		pre = lstack.top();
		lstack.pop();
		plast->next = pre;
		plast = pre;
	}
	plast->next = NULL;
	return pHead;
}
//合并链表
void merge(ListNode* pHead,int n){
	ListNode* pTemp1 = pHead,*pTemp2,*pTemp;
	if(n%2 == 0)
		n = n/2;
	else
		n = n/2+1;
	while(n-1){
		pTemp1 = pTemp1->next;
		n--;
	}
	pTemp = pTemp1->next;
	pTemp1->next = NULL;
	//逆置
	pTemp = Reverse(pTemp);
	//合并
	while(pTemp != NULL){
		pTemp1 = pHead->next;
		pTemp2 = pTemp->next;
		pTemp->next = pHead->next;
		pHead->next = pTemp;
		pHead  = pTemp1;
		pTemp  = pTemp2;
	}
	return;	
}

int main(){
	ListNode* pHead = NULL;
	AddToList(&pHead,1);
	AddToList(&pHead,2);
	AddToList(&pHead,3);
	AddToList(&pHead,4);
	AddToList(&pHead,5);
	//AddToList(&pHead,6);
	ListNode* pHead1 = pHead;
	pHead1 = Reverse(pHead1);
	pHead = pHead1;
	while(pHead1->next != NULL){
		printf("%d->",pHead1->value);
		pHead1 = pHead1->next;
	}
	printf("%d\n",pHead1->value);
	//递归
	pHead1 = pHead;
	pHead1 = Reverse_recurve(pHead1);
	pHead = pHead1;
	while(pHead1->next != NULL){
		printf("%d->",pHead1->value);
		pHead1 = pHead1->next;
	}
	printf("%d\n",pHead1->value);
	//栈
	pHead1 = pHead;
	pHead1 = Reverse_stack(pHead1);
	pHead = pHead1;
	while(pHead1->next != NULL){
		printf("%d->",pHead1->value);
		pHead1 = pHead1->next;
	}
	printf("%d\n",pHead1->value);
	//微软题目
	pHead1 = pHead;
	int len = ListLen(pHead);
	merge(pHead,len);
	while(pHead->next != NULL){
		printf("%d->",pHead->value);
		pHead = pHead->next;
	}
	printf("%d\n",pHead->value);
	system("PAUSE");
	return 0;
}
输出结果如下:




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值