题目:编写代码,以给定的x为基准值将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前。
解法一:交换结点法,回想学习快速排序的时候,也是以基准值将一组数划分成两部分,小于基准值的排在前面,大于基准值的排在后半部分。因此解决这个问题也可以使用两个指针。如果链表头结点开始遍历,第一个需要移动的结点是第一个大于或等于基准值的结点,例如链表1->3->6->7->2->1->5,基准值设为4,那么第一个指针滑到6的时候应该停止,它需要被交换到后面,因为6前面的结点值都是小于基准值的,所以和它交换的结点应该在它后面,需要找到一个小于基准值的结点交换到前面去,于是找到了结点2。交换结点6和2。然后两个指针同时后移一位,在寻找需要交换的结点过程中指针一直滑到链表结尾时,表明链表中已经没有需要交换的结点,这时候直接返回,循环结束。
void Partition(ListNode* pHead, int n)
{
if(pHead == NULL)
return;
ListNode *pCurr, *pNext;
pCurr = pHead;
while(pCurr->m_nValue < n)
{
pCurr = pCurr->m_pNext;
if(pCurr == NULL)
return;
}
pNext = pCurr;
while(pNext->m_nValue >= n)
{
pNext = pNext->m_pNext;
if(pNext == NULL)
return;
}
while(pCurr != NULL && pNext != NULL)
{
while(pCurr->m_nValue < n)
{
pCurr = pCurr->m_pNext;
if(pCurr == NULL)
return;
}
while(pNext->m_nValue >= n)
{
pNext = pNext->m_pNext;
//替换注释部分
if(pNext == NULL)
return;
}
int tmp = pCurr->m_nValue;
pCurr->m_nValue = pNext->m_nValue;
pNext->m_nValue = tmp;
pCurr = pCurr->m_pNext;
pNext = pNext->m_pNext;
}
}
解法二:先分割再合并。创建两个链表,before和after,before保存小于基准值的结点,after保存大于或等于基准值的结点,最后将两个链表合并。
void Partition(ListNode** pHead, int n)
{
if(pHead == NULL)
return;
ListNode *beforeHead, *beforeEnd, *afterHead;
beforeHead = beforeEnd = afterHead = NULL;
ListNode* pNode = *pHead;
while(pNode != NULL)
{
ListNode* node = pNode->m_pNext;
if(pNode->m_nValue < n)
{
if(beforeHead == NULL)
{
beforeHead = pNode;
beforeEnd = pNode;
beforeEnd->m_pNext = NULL;
}
else
{
pNode->m_pNext = beforeHead;
beforeHead = pNode;
}
}
else
{
if(afterHead == NULL)
{
afterHead = pNode;
afterHead->m_pNext = NULL;
}
else
{
pNode->m_pNext = afterHead;
afterHead = pNode;
}
}
pNode = node;
}
if(beforeHead == NULL)
{
*pHead = afterHead;
return;
}
beforeEnd->m_pNext = afterHead;
*pHead = beforeHead;
}