description:

given two sorted singly list, merge them into one using constant additional space

algorithm:

we will reference the two linked list as list1 and list2 for convenience,

since list1 is sorted,just find the right position for each element in list2,

detailed comments are added to the following code

ps: the blog has been modified since some bugs have been tested

the former version below is correct while the latter is wrong, I keep it just to remind myself to be independent and critical-thinking

// Definition for singly-linked list.
struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};

class Solution {
public:
    ListNode *sortList(ListNode *head) {
		if(head == NULL)
			return NULL;
		ListNode* mid,*end;
		int len;
		getPara(head,&mid,&end,&len);
		//cout << len << endl;  //only for debug
		if(len == 1){
			return head;
		}
		if(len == 2){
			if(head->val > head->next->val){
				int tmp = head->val;
				head->val = head->next->val;
				head->next->val = tmp;
			}
			return head;
		}

		end->next = NULL;
		 ListNode* latterpart = sortList(mid->next,end,len >> 1);
		mid->next = NULL;
		//传入值之前修改这个可能更好
		ListNode* formerpart = sortList(head,mid,(len+1)>>1);  //为什么formerpart会变为空指针

		head = Merge(formerpart,latterpart);
		return head;
	}
	void getPara(ListNode* head, ListNode**pmid,ListNode** pend,int*len){
		(*len) = 0;
		(*pmid) = head;
		(*pend) = head;
		if(head == NULL){
			return;
		}
		//ListNode* (*pend) = head,*slowpointer = head;
		(*len) = 1; //长度至少为1
		while((*pend)->next != NULL && (*pend)->next->next != NULL){ //快指针每次向后跳两步,慢指针每次向后跳一步
			(*pmid) = (*pmid)->next;
			(*pend) = (*pend)->next->next;
			(*len) += 2;
		}
		if((*pend)->next == NULL){  //长度为奇数
			return;
		}
		if((*pend)->next->next == NULL){ //长度为偶数
			(*len) += 1;
			(*pend) = (*pend)->next;
			return;
		}
	}
	ListNode* sortList(ListNode* head,ListNode* end,int len){
		if(len == 0){  //这里的条件太泛了所以貌似是写错了
			return NULL;
		}
		if(len == 1){
			head->next =NULL;  //注意修改
			return head;
		}
		if(len == 2){
			if(head->val > end->val){
				int tmp = end->val;
				end->val = head->val;
				head->val = tmp;
			}
			end->next = NULL;
			return head;
		}
		//int a[25] = {1,3,6,7,8,9,56,67,211,763,2,4,5,10,11,12,13,300,500,800};
		ListNode* newmid,*newend;
		int halflen;
		getPara(head,&newmid,&newend,&halflen);  //此处其实还可以优化,但出于代码复用的考虑

		newend->next = NULL;
		ListNode* latterpart = sortList(newmid->next,newend,halflen >> 1);
		newmid->next = NULL;
		ListNode* formerpart = sortList(head,newmid,(halflen+1)>>1);

		head = Merge(formerpart,latterpart);
		return head;
	}
	ListNode* Merge(ListNode* part1, ListNode*part2){  //Merge这里写的有问题诶
		if(part1 == NULL)
			return part2;
		if(part2 == NULL)
			return part1;
		//part1 != NULL && part2 != NULL
		ListNode* tmpp1 = part1, *tmpp2 = part2;
		bool first = true; //finally figured out the reason to use first,to indicate whether it's the first comparison
		ListNode* head = NULL;
		ListNode* last = NULL;
		ListNode* tmpformer = NULL;
		while(tmpp1 != NULL && tmpp2 != NULL){
			bool enterloop = false;;
			while(tmpp1 != NULL && tmpp2->val >= tmpp1->val){
			//if and only if the condition in while loop is satisfied the control flow can reach here
				tmpformer = tmpp1;
				if(first){
					first = false;
					head = tmpformer;
				}
				enterloop = true;
				tmpp1 = tmpp1->next;
			}
			if(tmpp1 == NULL){  //even if the big while is first carried out, control flow might reach here
				tmpformer->next = tmpp2;
				if(first){
					first = false;
					head = part1;
				}
				return head;
			}
			ListNode* tmpnextoftmpp2 = tmpp2->next;
			tmpp2->next = tmpp1;
			if(enterloop){
				tmpformer->next = tmpp2;
				//last = tmpp2;
				if(first){
					first = false;
					head = part1;
				}
			}
			else{
				if(last != NULL){
					last->next = tmpp2;
				}
				if(first){
					first = false;
					head = tmpp2;
				}
			}
			last = tmpp2;
			tmpp2 = tmpnextoftmpp2;

			//last = tmpformer;
		}
		return head;
	}
};

  

#include<iostream>
#include<cstdio>
#include<string.h>
#include<string>
#include<cstring>
#include<algorithm>

using namespace std;

class Node{
public:
	int value;
	Node* Next;
	Node(int v_ = 0, Node* Next_ = NULL):value(v_),Next(Next_){}
};
/*Node* Merge2(Node* head1, Node* head2)
{
	Node* res,*ret;
	if(head1 == NULL) return head2;
	if(head2 == NULL) return head1;
	Node* p = head1;
	Node* q = head2;
	
	if(p->value < q->value)
	{
		res = p;
		p = p->Next;
	}
	else
	{
		res = q;
		q = q->Next;
	}
	ret = res;
	while(p && q)
	{
		if(p->value < q->value)
		{
			res->Next = p;
			res = p;
			p = p->Next;
		}
		else
		{
			res->Next = q;
			res = q;
			q = q->Next;
		}
	}
	while(p)
	{
	         res->Next = p;
                  res = p;
		p = p->Next;
	}
	while(q)
	{
		res->Next = q;
		res = q;
		q = q->Next;
	}
	return ret;
}*/
Node* Merge2(Node*p1,Node*p2){
	if(p1 == NULL)
		return p2;
	if(p2 == NULL)
		return p1;
	Node *tmpp1 = p1,*tmpp2 = p2;
	Node*head;
	bool first = true;
	/*core optimization: if tmpp2 find its place in list1, then tmpp2->next must be after its position,so both list1 and list2
	  are enumerated only once, which implements linear algorithm*/
	while(tmpp1 != NULL && tmpp2 != NULL){
		Node* tmpformer = NULL;
		while(tmpp1 != NULL && tmpp2->value > tmpp1->value){ 
			tmpformer = tmpp1;
			tmpp1 = tmpp1->Next;
		}
		if(tmpp1 == NULL){
			tmpformer->Next = tmpp2;
			if(first){
				first = false;
				head = p1;
			}
			break;
		}
		//tmpp2的value值比tmpp1的value值小但是比tmpformer的value值大
		Node* tmprecordp2 = tmpp2->Next;
		tmpp2->Next = tmpp1;
		if(tmpformer != NULL){
			tmpformer->Next = tmpp2;
			if(first){
				first = false;
				head = p1;
			}
		}
		else{
			if(first){
				first = false;
				head = p2;
			}
		}
		tmpp2 = tmprecordp2;
	}
	return head;
}
int main(){
	Node* p1[10], *p2[10];
	memset(p1,0,sizeof(p1));
	memset(p2,0,sizeof(p2));
	int a[25] = {1,3,6,7,8,9,56,67,211,763,2,4,5,10,11,12,13,300,500,800};
	/*initalization*/
	for(int i = 0; i < 10; ++i){
		p1[i] = new Node(a[i]);
	}
	for(int i = 0; i < 10; ++i){
		p2[i] = new Node(a[10+i]);
	}
	Node* pp1,*pp2;

	for(int i = 0; i < 9; ++i){
	//	cout << &(p1[i]->Next) << endl;
		p1[i]->Next = p1[i+1];
	}
	for(int i = 0; i < 9; ++i){
		p2[i]->Next = p2[i+1];
	}
		pp1 = p1[0];
	while(pp1 != NULL){
		cout << pp1->value << '\t';
		pp1 = pp1->Next;
	}
	cout << endl;
	pp2 = p2[0];
	while(pp2 != NULL){
		cout << pp2->value << '\t';
		pp2 = pp2->Next;
	}
	cout << endl;
	/*initialization end*/
	Node* res = Merge2(p1[0],p2[0]);
	while(res!=NULL){
		cout << res->value << endl;
		res = res->Next;
	}
	for(int i = 0; i < 10; ++i){
		delete p1[i];
	}
	for(int i = 0; i < 10; ++i){
		delete p2[i];
	}
	return 0;
}

key points:

1.pay special attention to keep head pointer, which is easily lost,

  my solution is to set a flag bool variance, which is linear complexity but somewhat inefficient

  perhaps it has potential to improve

2.avoid misorder of pointer

3.special condition: if (p1 == NULL) return p2;

                            if(p2 == NULL ) return p1;

4.when search for the postion for a certain element in list1, note that it might be above any element in list1 so tmpp1 might reach its end(value equals NULL) during search

posted on 2014-04-27 21:44  mizz  阅读(215)  评论(0编辑  收藏  举报