1. 程式人生 > >有序連結串列的操作

有序連結串列的操作

有序連結串列的合併

要想合併後依舊有序,其實質是比較連結串列的值,按大小排序。

假設現給定兩個有序連結串列分別如下:

List1 = (1, 3, 4, 5), List2 = (1, 2, 5, 7, 8, 9),則合併後的有序連結串列List3 = (1, 1, 2, 3, 4, 5, 5, 7, 8, 9)

從上述分析可知,首先對於List1和List2是有序的,我們只需用兩個指標cur1和cur2分別指向List1和List2,然後依次向後比遍歷並進行資料的比較。

由於List1的連結串列長度比List2的連結串列長度要小,則當List1為空的時候,List2剩餘的元素的值一定是大於List1的最後一個值,此時只需要將List2的剩餘資料插入到result後面即可。

非遞迴方法實現:

List *MergeList(List *pList1, List *pList2)
{
	List *cur1 = pList1;           //指向連結串列1
	List *cur2 = pList2;           //指向連結串列2
	List *result = NULL;          //儲存合併後的連結串列
	List *tail = NULL;            
	List *node;
	List *last;
	while(cur1 != NULL && cur2 != NULL)
	{
//比較連結串列1和連結串列2的值的大小
		if(cur1->data > cur2->data)
		{
			node = cur2;
		}else
		{
			node = cur1;
		}
		last = node->next;
//將值存入result
		if(result != NULL)
		{
			tail->next = node;
		}else
		{
			result = node;
		}
		node->next = NULL;
		tail = node;
		if(node == cur1)
		{
			cur1 = last;
		}else
		{
			cur2 = last;
		}
	}
//如果連結串列1為空,就將連結串列2的剩餘內容加到result後面,反之亦然
	if(cur1 == NULL)
	{
		tail->next = cur2;
	}
	if(cur2 == NULL)
	{
		tail->next = cur1;
	}
	return result;
}	

遞迴方法實現:

List *MergeList(List *pList1, List *pList2)
{
	List *result = NULL;
	if(pList1 == NULL)
	{
		return pList2;
	}
	if(pList2 == NULL)
	{
		return pList1;
	}
	if(pList1->data > pList2->data)
	{
		result = pList2;
		result->next = MergeList(pList1, pList2->next);
	}else
	{
		result = pList1;
		result->next = MergeList(pList1->next, pList2);
	}
	return result;
}

如何得到兩個有序連結串列的相同資料呢?此題思路與合併有序連結串列的思路一致,即通過指標遍歷,比較資料的大小即可。程式碼實現如下:

void SameData(List *pList1, List *pList2)
{
	List *cur1 = pList1;
	List *cur2 = pList2;
	while(cur1 != NULL && cur2 != NULL)
	{
		if(cur1->data > cur2->data)
		{
			cur2 = cur2->next;
		}else if(cur1->data < cur2->data)
		{
			cur1 = cur1->next;
		}else
		{
			printf("%d", cur1->data);
			cur1 = cur1->next;
			cur2 = cur2->next;
		}
	}
}

對於有序連結串列的合併問題,本程式碼實現的是不帶頭結點的有序單鏈表。對於帶有頭結點的兩個有序單鏈表的合併,思路大體一致,其中值得注意的一點就是頭結點的釋放。由於兩個單鏈表都具有頭結點,當合並完成後,只需保留一個頭結點,即釋放掉另一個頭結點。舉例:

觀察下圖:經過第一次比較之後,我們發現 0 < 1, 此時需要將List1的第一個結點儲存到result中,由於頭結點的next域中存放的是連結串列的第一個結點的起始地址,此時只需要將List1的頭結點作為result的頭結點即可。當連結串列合併完成之後,此時連結串列2除頭結點之外,已經全部存入新連結串列,則需要釋放List2的頭結點即可。