链表相关算法:
2015-03-12 20:25
387 查看
链表结点定义如下:
struct ListNode
{
int value;
ListNode * next;
};
算法一:从尾到头打印链表
//栈实现
void PrintListFromTaliToHead(ListNode *pHead)
{
std::stack<ListNode *> nodes;
ListNode *pNode=pHead;
while(pNode!=NULL)
{
nodes.push(pNode);
pNode=pNode->next;
}
while(!nodes.empty())
{
pNode=nodes.top();
printf("%d\t",pNode->value);
nodes.pop();
}
}
//递归实现
void PrintListFromTaliToHead(ListNode *pHead)
{
if(pHead!=NULL)
{
if(pHead->next!=NULL)
{
PrintListFromTaliToHead(pHead->next);
}
printf("%d\t",pHead->value);
}
}
算法2:在O(1)时间删除链表结点[前提:删除结点在链表中即排除删除结点存在问题]
void DeleteNode(ListNode ** pHead, ListNode *pToBeDeleted)
{
if(!pHead || !pToBeDeleted)
return;
//要删除的结点不是尾结点
if(pToBeDeleted->next !=NULL)
{
ListNode *pNext=pToBeDeleted->next;
pToBeDeleted->value=pNext->value;
pToBeDeleted->next=pNext->next;
delete pNext;
pNext=NULL;
}
//链表只有一个结点,删除头结点(也是尾结点)
else if(*pHead==pToBeDeleted)
{
delete pToBeDeleted;
pToBeDeleted=NULL;
*pHead=NULL;
}
//链表中有多个结点,删除尾结点
else
{
ListNode *pNode=*pHead;
while(pNode->next != pToBeDeleted)
{
pNode=pNode->next;
}
pNode->next=NULL;
delete pToBeDeleted;
pToBeDeleted=NULL:
}
}
算法3:链表中的倒数第k个结点
分析:(1)倒数第k个结点即第n-k+1个 结点,需要遍历两次链表,第一次得到链表长度n,第二次找到倒数第k个结点。(2)一次遍历链表:定义两个指针,第一个指针从链表头指针开始遍历向前走k-1步,从第k步开始,第二个指针也开始遍历链表。当第一个指针到达链表的尾结点时,第二个指针正好是倒数第k个结点。
注意需要考虑的三个问题:输入的pHead为空指针;输入的以pListHead为头结点的链表的结点总数少于k;输入的参数k为0。
ListNode *FindKthToTail(ListNode *pHead, unsigned int k)
{
if(pHead==NULL || k=0)
return NULL;
ListNode *pAhead=pHead;
ListNode *pBehide=NULL;
for(unsigned int i=0; i<k-1;i++)
{
if(pAhead->next != NULL)
pAhead=pAhead->next;
else
return NULL;
}
pBehide=pHead;
while(pAhead->next != NULL)
{
pAhead=pAhead->next;
pBehide=pBehide->next;
}
return pBehide;
}
同类相关题目:(1)求链表的中间结点
ListNode * searchMid(ListNode *pHead)
{
ListNode *temp=pHead;
while(pHead->next->next != NULL)
{
head=head->next->next;
temp=temp->next;
}
return temp;
}
(2)判断一个单链表是否形成了环形结构
分析:定义两个指针,同时从链表的头出发,一个指针一次走一步,另一个指针一次走两步,如果走得快的指针追上了走得慢的指针,那么链表就是环形链表;如果走得快的指针走到最后都没追上第一个指针,那么链表就不是环形链表。
算法4:反转链表
ListNode *ReverseList(ListNode *pHead)
{
ListNode *pReverseHead=NULL;
ListNode *pNode=pHead;
ListNode *pPrev=NULL;
while(pNode != NULL)
{
ListNode *pNext=pNode->next;
if(pNext==NULL)
pReverseHead=pNode;
pNode->next=pPrev;
pPrev=pNode;
pNode=pNext;
}
return pReversedHead;
}
算法5:合并两个排序链表(递归)
ListNode *Merge(ListNode *pHead1, ListNode *pHead2)
{
if(pHead1==NULL)
return pHead2;
else if(pHead2==NULL)
return pHead1;
ListNode *pMergedHead = NULL;
if(pHead1->value < pHead2->value)
{
pMergedHead=pHead1;
pMergedHead->next=Merge(pHead1->next, pHead2);
}
else
{
pMergedHead=pHead2;
pMergedHead->next=Merge(pHead1, pHead2->next);
}
return pMergedHead;
}
算法6:两个链表的第一个公共结点
(1)两个辅助栈,分别用于存储链表结点。比较两个栈顶的结点是否相同,如果相同,继续比较,直到找到最后一个相同的结点。空间复杂度O(m+n),时间复杂度O(m+n)
(2)首先遍历两个链表得到它们的长度,第二次遍历时,较长的链表先走几步,然后同时在链表上遍历,找到第一个相同的结点就是第一个公共的结点。
ListNode *FindFirstCommonNode(ListNode *pHead1, ListNode *pHead2)
{
//得到两个链表的长度
unsigned int nLength1=GetListLength(pHead1);
unsigned int nLength2=GetListLength(pHead2);
int nLengthDif=nLength1-nLength2;
ListNode *pHeadLong=pHead1;
ListNode *pHeadShort=pHead2;
if(nLength2>nLength1)
{
nLengthDif=nLength2-nLength1;
pHeadLong=pHead2;
pHeadShort=pHead1;
}
for(int i=0; i<nLengthDif; ++i)
pHeadLong=pHeadLong->next;
while((pHeadLong != NULL) && (pHeadShort !=NULL) && (pHeadLong != pHeadShort))
{
pHeadLong=pHeadLong->next;
pHeadShort=pHeadShort->next;
}
//得到第一个公共结点
ListNode *pFirstCommonNode=pHeadLong;
retrun pFirstCommonNode;
}
unsigned int GetListLength(ListNode *pHead)
{
unsigned int nLength=0;
ListNode *pNode=pHead;
while(pNode != NULL)
{
++nLength;
pNode=pNode->next;
}
return nLength;
}
算法7:圆圈中最后剩下的数字(环形链表)
题目:0到n-1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字,求出这个圆圈中剩下的最后一个数字。
解法一:用环形链表模拟圆圈
每删除一个数字需要m步运算,总共n个数字,时间复杂度O(mn),同时需要辅助链表,空间复杂度为O(n)
int LastRemaining(unsigned int n, unsigned int m)
{
if(n<1 || m<1)
return -1;
unsigned int i=0;
list<int>numbers;
for(i=0; i<n; i++)
{
numbers.push_back(i);
}
list<int> :: iterator current=numbers.begin();
while(numbers.size()>1)
{
for(int i=1; i<m; ++i)
{
current++;
if(current==numbers.end())
current=numbers.begin();
}
list<int> :: iterator next = ++current;
if(next == numbers.end())
next=numbers.begin();
- - current;
numbers.erase(current);
current=next;
}
return *(current);
}
解法二:分析每次被删除的数字的规律并直接计算出圆圈中最后剩下的数字(待完善)
算法8:二叉搜索树与双向链表(双向链表)
题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
struct BinaryTreeNode
{
int value;
BinaryTreeNode *left;
BinaryTreeNode *right;
};
BinaryTreeNode * Covert(BinaryTreeNode *pRootOfTree)
{
BinaryTreeNode *pLastNodeInList=NULL;//已经转换好的链表的最后一个结点
CovertNode(pRootOfTree, &pLastNodeInList);
//pLastNodeInList指向双向链表的尾结点,我们需要返回头结点
BinaryTreeNode *pHeadOfList=pLastNodeInList;
while(pHeadOfList != NULL && pHeadOfList->left != NULL)
pHeadOfList=pHeadOfList->left;
return pHeadOfList;
}
void ConvertNode(BinaryTreeNode *pNode, BinaryTreeNode **pLastNodeInList)
{
if(pNode==NULL)
return;
BinaryTreeNode *pCurrent=pNode;
if(pCurrent->left !=NULL)
CovertNode(pCurrent->left,
pLastNodeInList);
pCurrent->left= *pLastNodeInList;
if(*pLastNodeInList != NULL)
(*pLastNodeInList)->right=pCurrent;
*pLastNodeInList=pCurrent;
if(pCurrent->right !=NULL)
CovertNode(pCurrent->right, pLastNodeInList);
}
用pLastNodeInList指向已经转换好的链表的最后一个结点(即最大值结点)
算法9:复杂链表的复制(复杂链表)
待续。。。。。
struct ListNode
{
int value;
ListNode * next;
};
算法一:从尾到头打印链表
//栈实现
void PrintListFromTaliToHead(ListNode *pHead)
{
std::stack<ListNode *> nodes;
ListNode *pNode=pHead;
while(pNode!=NULL)
{
nodes.push(pNode);
pNode=pNode->next;
}
while(!nodes.empty())
{
pNode=nodes.top();
printf("%d\t",pNode->value);
nodes.pop();
}
}
//递归实现
void PrintListFromTaliToHead(ListNode *pHead)
{
if(pHead!=NULL)
{
if(pHead->next!=NULL)
{
PrintListFromTaliToHead(pHead->next);
}
printf("%d\t",pHead->value);
}
}
算法2:在O(1)时间删除链表结点[前提:删除结点在链表中即排除删除结点存在问题]
void DeleteNode(ListNode ** pHead, ListNode *pToBeDeleted)
{
if(!pHead || !pToBeDeleted)
return;
//要删除的结点不是尾结点
if(pToBeDeleted->next !=NULL)
{
ListNode *pNext=pToBeDeleted->next;
pToBeDeleted->value=pNext->value;
pToBeDeleted->next=pNext->next;
delete pNext;
pNext=NULL;
}
//链表只有一个结点,删除头结点(也是尾结点)
else if(*pHead==pToBeDeleted)
{
delete pToBeDeleted;
pToBeDeleted=NULL;
*pHead=NULL;
}
//链表中有多个结点,删除尾结点
else
{
ListNode *pNode=*pHead;
while(pNode->next != pToBeDeleted)
{
pNode=pNode->next;
}
pNode->next=NULL;
delete pToBeDeleted;
pToBeDeleted=NULL:
}
}
算法3:链表中的倒数第k个结点
分析:(1)倒数第k个结点即第n-k+1个 结点,需要遍历两次链表,第一次得到链表长度n,第二次找到倒数第k个结点。(2)一次遍历链表:定义两个指针,第一个指针从链表头指针开始遍历向前走k-1步,从第k步开始,第二个指针也开始遍历链表。当第一个指针到达链表的尾结点时,第二个指针正好是倒数第k个结点。
注意需要考虑的三个问题:输入的pHead为空指针;输入的以pListHead为头结点的链表的结点总数少于k;输入的参数k为0。
ListNode *FindKthToTail(ListNode *pHead, unsigned int k)
{
if(pHead==NULL || k=0)
return NULL;
ListNode *pAhead=pHead;
ListNode *pBehide=NULL;
for(unsigned int i=0; i<k-1;i++)
{
if(pAhead->next != NULL)
pAhead=pAhead->next;
else
return NULL;
}
pBehide=pHead;
while(pAhead->next != NULL)
{
pAhead=pAhead->next;
pBehide=pBehide->next;
}
return pBehide;
}
同类相关题目:(1)求链表的中间结点
ListNode * searchMid(ListNode *pHead)
{
ListNode *temp=pHead;
while(pHead->next->next != NULL)
{
head=head->next->next;
temp=temp->next;
}
return temp;
}
(2)判断一个单链表是否形成了环形结构
分析:定义两个指针,同时从链表的头出发,一个指针一次走一步,另一个指针一次走两步,如果走得快的指针追上了走得慢的指针,那么链表就是环形链表;如果走得快的指针走到最后都没追上第一个指针,那么链表就不是环形链表。
算法4:反转链表
ListNode *ReverseList(ListNode *pHead)
{
ListNode *pReverseHead=NULL;
ListNode *pNode=pHead;
ListNode *pPrev=NULL;
while(pNode != NULL)
{
ListNode *pNext=pNode->next;
if(pNext==NULL)
pReverseHead=pNode;
pNode->next=pPrev;
pPrev=pNode;
pNode=pNext;
}
return pReversedHead;
}
算法5:合并两个排序链表(递归)
ListNode *Merge(ListNode *pHead1, ListNode *pHead2)
{
if(pHead1==NULL)
return pHead2;
else if(pHead2==NULL)
return pHead1;
ListNode *pMergedHead = NULL;
if(pHead1->value < pHead2->value)
{
pMergedHead=pHead1;
pMergedHead->next=Merge(pHead1->next, pHead2);
}
else
{
pMergedHead=pHead2;
pMergedHead->next=Merge(pHead1, pHead2->next);
}
return pMergedHead;
}
算法6:两个链表的第一个公共结点
(1)两个辅助栈,分别用于存储链表结点。比较两个栈顶的结点是否相同,如果相同,继续比较,直到找到最后一个相同的结点。空间复杂度O(m+n),时间复杂度O(m+n)
(2)首先遍历两个链表得到它们的长度,第二次遍历时,较长的链表先走几步,然后同时在链表上遍历,找到第一个相同的结点就是第一个公共的结点。
ListNode *FindFirstCommonNode(ListNode *pHead1, ListNode *pHead2)
{
//得到两个链表的长度
unsigned int nLength1=GetListLength(pHead1);
unsigned int nLength2=GetListLength(pHead2);
int nLengthDif=nLength1-nLength2;
ListNode *pHeadLong=pHead1;
ListNode *pHeadShort=pHead2;
if(nLength2>nLength1)
{
nLengthDif=nLength2-nLength1;
pHeadLong=pHead2;
pHeadShort=pHead1;
}
for(int i=0; i<nLengthDif; ++i)
pHeadLong=pHeadLong->next;
while((pHeadLong != NULL) && (pHeadShort !=NULL) && (pHeadLong != pHeadShort))
{
pHeadLong=pHeadLong->next;
pHeadShort=pHeadShort->next;
}
//得到第一个公共结点
ListNode *pFirstCommonNode=pHeadLong;
retrun pFirstCommonNode;
}
unsigned int GetListLength(ListNode *pHead)
{
unsigned int nLength=0;
ListNode *pNode=pHead;
while(pNode != NULL)
{
++nLength;
pNode=pNode->next;
}
return nLength;
}
算法7:圆圈中最后剩下的数字(环形链表)
题目:0到n-1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字,求出这个圆圈中剩下的最后一个数字。
解法一:用环形链表模拟圆圈
每删除一个数字需要m步运算,总共n个数字,时间复杂度O(mn),同时需要辅助链表,空间复杂度为O(n)
int LastRemaining(unsigned int n, unsigned int m)
{
if(n<1 || m<1)
return -1;
unsigned int i=0;
list<int>numbers;
for(i=0; i<n; i++)
{
numbers.push_back(i);
}
list<int> :: iterator current=numbers.begin();
while(numbers.size()>1)
{
for(int i=1; i<m; ++i)
{
current++;
if(current==numbers.end())
current=numbers.begin();
}
list<int> :: iterator next = ++current;
if(next == numbers.end())
next=numbers.begin();
- - current;
numbers.erase(current);
current=next;
}
return *(current);
}
解法二:分析每次被删除的数字的规律并直接计算出圆圈中最后剩下的数字(待完善)
算法8:二叉搜索树与双向链表(双向链表)
题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
struct BinaryTreeNode
{
int value;
BinaryTreeNode *left;
BinaryTreeNode *right;
};
BinaryTreeNode * Covert(BinaryTreeNode *pRootOfTree)
{
BinaryTreeNode *pLastNodeInList=NULL;//已经转换好的链表的最后一个结点
CovertNode(pRootOfTree, &pLastNodeInList);
//pLastNodeInList指向双向链表的尾结点,我们需要返回头结点
BinaryTreeNode *pHeadOfList=pLastNodeInList;
while(pHeadOfList != NULL && pHeadOfList->left != NULL)
pHeadOfList=pHeadOfList->left;
return pHeadOfList;
}
void ConvertNode(BinaryTreeNode *pNode, BinaryTreeNode **pLastNodeInList)
{
if(pNode==NULL)
return;
BinaryTreeNode *pCurrent=pNode;
if(pCurrent->left !=NULL)
CovertNode(pCurrent->left,
pLastNodeInList);
pCurrent->left= *pLastNodeInList;
if(*pLastNodeInList != NULL)
(*pLastNodeInList)->right=pCurrent;
*pLastNodeInList=pCurrent;
if(pCurrent->right !=NULL)
CovertNode(pCurrent->right, pLastNodeInList);
}
用pLastNodeInList指向已经转换好的链表的最后一个结点(即最大值结点)
算法9:复杂链表的复制(复杂链表)
待续。。。。。
相关文章推荐