本例中单链表未添加头结点。
结点定义为:
struct ListNode
{
int data;
ListNode* next;
ListNode(int x) :data(x), next(nullptr) {}
};
1 单链表尾部添加结点
void AddToTail(ListNode** pHead, int value)
{
ListNode* pNew = new ListNode(value);
if (*pHead == nullptr)
*pHead = pNew;
else
{
ListNode* pNode = *pHead;
while (pNode->next != nullptr)
pNode = pNode->next;
pNode->next = pNew;
}
}
2 删除第i个结点,认为链表非空。
bool DeleteNode(ListNode** pHead, int n)
{
if (n == 1)
{
*pHead = (*pHead)->next;
return true;
}
ListNode* pNode = *pHead;
int j = 1;
while (pNode->next && j < n-1)
{
pNode = pNode->next;
j++;
}
if (!(pNode->next) || j != n-1)
return false;
ListNode* pDelete = pNode->next;
pNode->next = pDelete->next;
delete pDelete;
pDelete = nullptr;
return true;
}
3 第i个位置前插入结点
bool InSertList(ListNode** pHead, int pos, int value)
{
ListNode* pNew = new ListNode(value);
if (pos == 1)
{
pNew->next = *pHead;
*pHead = pNew;
return true;
}
int j = 1;
ListNode* pNode = *pHead;
while (pNode && j<pos-1)
{
pNode = pNode->next;
j++;
}
if (!pNode || j!=pos-1)
return false;
ListNode* pNext = pNode->next;
pNode->next = pNew;
pNew->next = pNext;
return true;
}
4 从尾到头打印链表,通常打印是只读操作。方法一利用栈实现,未修改链表结构。
void PrintListReverse(ListNode* pHead)
{
stack<int> nodes;
ListNode* pNode = pHead;
while (pNode)
{
nodes.push(pNode->data);
pNode = pNode->next;
}
while (!nodes.empty())
{
cout << nodes.top() << ' ';
nodes.pop();
}
}
方法二反转链表,改变了链表结构。打印部分略去。
ListNode* ReverseList(ListNode* pHead)
{
ListNode* pReverseHead = nullptr; //建立返回值,简化输入
ListNode* pPrev = nullptr;
ListNode* pNode = pHead;
while (pNode)
{
ListNode* pNext = pNode->next;
if (!pNext)
pReverseHead = pNode; //不立即返回的原因是还要再连接pNode与pPrev
pNode->next = pPrev;
pPrev = pNode;
pNode = pNext;
}
return pReverseHead;
}
5 给定单链表头指针和一个结点(待删除的)指针,o(1)时间内删除该结点
将结点后一位的值赋给前一位,再将后一位删除。要注意的情况有删除的结点是否为尾结点;
链表中是否只有一个结点;并默认待删除的结点位于链表之内。
void DeleteNode(ListNode** pHead, ListNode* pToDelete)
{
if (!pHead || !pToDelete)
return;
if (pToDelete->next) //不是尾结点
{
ListNode* pNext = pToDelete->next;
pToDelete->data = pNext->data;
pToDelete->next = pNext->next;
delete pNext;
pNext = nullptr;
}
else if (*pHead == pToDelete) //只有一个结点
{
delete pToDelete;
pToDelete = nullptr;
*pHead = nullptr;
}
else //是尾结点
{
ListNode* pNode = *pHead;
while (pNode->next != pToDelete)
pNode = pNode->next;
delete pToDelete;
pToDelete = nullptr;
pNode->next = nullptr;
}
}
6 输入一个链表,输出链表的倒数第k个结点, 从1开始计数。
单链表使用两个指针可以在遍历一遍的情况下,完成任务。
ListNode* FindLastK(ListNode* pHead, int k)
{
if (!pHead || k < 1)
return nullptr;
ListNode* pAhead = nullptr;
ListNode* pBehind = pHead;
for (int i=0;i<k-1;++i)
{
pBehind = pBehind->next;
if (!pBehind)
return nullptr;
}
pAhead = pHead;
while (pBehind->next)
{
pAhead = pAhead->next;
pBehind = pBehind->next;
}
return pAhead;
}
7 合并两个排序的链表
输入两个递增排序的链表,合并两个链表使结点仍是递增排序的。举例1–3-5-7,2-4-6-8
1-2-3-4-5-6-7-8. 相同重复的问题考虑递归调用。
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
if (!pHead1)
return pHead2;
else if (!pHead2)
return pHead1;
ListNode* pHeadMerge = nullptr;
if (pHead1->data > pHead2->data)
{
pHeadMerge = pHead2;
pHeadMerge->next = Merge(pHead1, pHead2->next);
}
else
{
pHeadMerge = pHead1;
pHeadMerge->next = Merge(pHead1->next, pHead2);
}
return pHeadMerge;
}
8 复杂链表的复制。每个结点除了有一个next指针指向下一个结点,还有一个pBling指向链表的任意结点。大问题化分成一个个的小问题。找到影响效率的关键,再找效率高的替代解决方案。
结点定义为:
struct complexListNode
{
int data;
complexListNode* next;
complexListNode* bling;
complexListNode(int x) :data(x), next(nullptr), bling(nullptr) {};
};
实现的有三部分,1 本来是A-B-C-D, 变为A-A’-B-B’-C-C’-D-D’;
void CloneNodes(complexListNode* pHead)
{
complexListNode* pNode = pHead;
while (pNode)
{
complexListNode* pNew = new complexListNode(pNode->data);
pNew->next = pNode->next;
pNode->next = pNew;
pNode = pNew->next;
}
}
2 将原有的A-B-C-D的bling的下一位赋给A’-B’-C’-D’.
void connectPBling(complexListNode* pHead)
{
complexListNode* pNode = pHead;
while (pNode)
{
complexListNode* pNodeClone = pNode->next;
if (pNode->bling)
pNodeClone->bling = pNode->bling->next;
pNode = pNodeClone->next;
}
}
3 拆分两个链表为 A-B-C-D和A’-B’-C’-D’
complexListNode* seperate(complexListNode* pHead)
{
complexListNode* pNode = pHead;
complexListNode* pHeadClone = pNode->next;
complexListNode* pNodeClone = pNode->next;
while (pNode)
{
pNode->next = pNodeClone->next;
pNode = pNode->next;
if (!pNode) //pNode到达尾部
break;
pNodeClone->next = pNode->next;
pNodeClone = pNodeClone->next;
}
return pHeadClone;
}
4 合起来为:
complexListNode* clone(complexListNode* pHead)
{
if (!pHead)
return nullptr;
CloneNodes(pHead);
connectPBling(pHead);
return seperate(pHead);
}
9 输入两个链表,找出它们的第一个公共结点。
ListNode* FindCommonNode(ListNode* pHead1, ListNode* pHead2)
{
if (!pHead1 || !pHead2)
return nullptr;
int length1 = 0, length2 = 0;
ListNode* pNode = pHead1;
while (pNode)
{
pNode = pNode->next;
length1++;
}
pNode = pHead2;
while (pNode)
{
pNode = pNode->next;
length2++;
}
int lenghtdif = length1 - length2;
ListNode* pHeadLong = pHead1;
ListNode* pHeadShort = pHead2;
if (length1 < length2)
{
pHeadLong = pHead2;
pHeadShort = pHead1;
lenghtdif = length2 - length1;
}
for (int i = 0; i < lenghtdif; ++i)
pHeadLong = pHeadLong->next;
while (pHeadLong && pHeadShort && pHeadLong!=pHeadShort)
{
pHeadLong = pHeadLong->next;
pHeadShort = pHeadShort->next;
}
return pHeadLong;
}
10 输入一颗二叉搜索树,将该二叉搜索树转换成排序的双向链表。只能调整树中结点指针的方向。
递归的一个重要思想,子问题已完成。大问题分解成小问题。
struct BinaryTreeNode
{
int data;
BinaryTreeNode* left;
BinaryTreeNode* right;
};
BinaryTreeNode* Convert(BinaryTreeNode* pRoot)
{
BinaryTreeNode* pLastNode = nullptr;
ConvertNode(pRoot, &pLastNode);
BinaryTreeNode* pHead = pLastNode;
while (pHead && pHead->left)
pHead = pHead->left;
return pHead;
}
void ConvertNode(BinaryTreeNode* pRoot, BinaryTreeNode** pLastNode)
{
if (!pRoot)
return;
BinaryTreeNode* pCurrent = pRoot;
if (pCurrent->left)
ConvertNode(pRoot->left, pLastNode);
pCurrent->left = *pLastNode;
if (*pLastNode)
(*pLastNode)->right = pCurrent;
*pLastNode = pCurrent;
if (pCurrent->right)
ConvertNode(pRoot->right, pLastNode);
}
11 0,1,….n-1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字。求圆圈里剩下的最后一个数字。
int LastNumLeft(int n, int m)
{
if (n < 1 || m < 1)
return -1;
list<int> li;
for (int i = 0; i < n; ++i)
li.push_back(i);
list<int>::iterator it = li.begin();
while (li.size()>1)
{
for (int i=0;i<m-1;++i)
{
if (it == li.end())
it = li.begin();
else
{
it++;
if (it == li.end())
it = li.begin();
}
}
it = li.erase(it);
if (it == li.end()) //删除为链表最后一个结点,赋值begin()
it = li.begin();
}
return li.front();
}