1. 程式人生 > >連結串列翻轉(每K個結點進行一次逆置)

連結串列翻轉(每K個結點進行一次逆置)

連結串列翻轉

給出一個連結串列和一個數k,比如連結串列1→2→3→4→5→6

若k=2,翻轉後2→1→4→3→6→5,

若k=3,翻轉後3→2→1→6→5→4,

若k=4,翻轉後4→3→2→1→5→6,

用程式實現Node* RotateList(Node* list, size_t k). 

我的思路是把每K個結點的逆置成的連結串列都當成一條新的連結串列,所以共有m=size/k條,然後再用上一條連結串列的尾tail和當前連結串列的頭newlist連線起來。所以要把每條連結串列的尾儲存起來,但是我們知道這是連結串列的逆置,所以還未逆置的部分的頭就是下條連結串列的尾,也就是程式碼中的head。最後再把剩下的連結串列鏈在新連結串列的尾部即可。


//逆置連結串列K
pList* RotateList(pList* pplist, size_t k)
{
	assert(*pplist);

	int m = Size(*pplist) / k;   //計算新連結串列的個數
	if (m <= 0 && k==1)
	{
		return NULL;
	}

	pNode cur = *pplist;
	pNode tail = cur;  //儲存當前連結串列的尾結點
	pList* Head = pplist;  //返回值,儲存整個連結串列的首節點

	for (int i = 0; i < m; i++)//迴圈逆置m條連結串列
	{
		pList newlist = NULL;  //每k個結點都當作一條新的連結串列
		pNode head = cur;  //當前連結串列的頭部,即下條連結串列的尾結點
		int K = k;
		while (K > 0)   //k個結點的逆置
		{
			pNode tmp = cur;
			cur = cur->next;
			tmp->next = newlist;
			newlist = tmp;
			K--;
		}

		if (i == 0)  //第一條逆置的新連結串列要做整個連結串列的頭
		{
			*Head = newlist;
		}
		else   //上條連結串列的尾和新連結串列連結起來
		{
			tail->next = newlist;
			tail = head;  //更新連結串列的尾
		}
	}

	while (cur)  //將剩餘的不夠k個的結點鏈在已經逆置好連結串列的尾部
	{
		tail->next = cur;
		tail = tail->next;
		cur = cur->next;
	}
	return Head;
}

測試:對一條連結串列進行多次逆置
void TestList()
{
	pList l1 = NULL;

	PushBack(&l1, 1);
	PushBack(&l1, 2);
	PushBack(&l1, 3);
	PushBack(&l1, 4);
	PushBack(&l1, 5);
	PushBack(&l1, 6);
	PushBack(&l1, 7);
	PushBack(&l1, 8);
	PushBack(&l1, 9);
	PushBack(&l1, 10);

	Print(l1);
	cout << endl;
	pList* ret1 = RotateList(&l1, 1);
	Print(*ret1);
	pList* ret2 = RotateList(&l1, 2);
	Print(*ret2);
	pList* ret3 = RotateList(&l1, 3);
	Print(*ret3);
	pList* ret4 = RotateList(&l1, 6);
	Print(*ret4);
}