链表常用操作

来源:互联网 发布:js获取cookie过期时间 编辑:程序博客网 时间:2024/05/22 06:43

原文:

http://blog.csdn.NET/walkinginthewind/article/details/7393134

1.求一个单向链表的节点个数

unsigned int GetCount(List *pHead) const{    unsigned int count = 0;    List *pTmp = pHead;    while(pTmp != NULL)    {        count++;        pTmp = pTmp->next;    }    return count;}

2.将单链表反转

List* ReverseList(List *pHead){    if(pHead == NULL || pHead->next == NULL)        return pHead;    List *pTmp = pHead;    List *pCur = pTmp;    List *pRev = NULL;    while(pTmp != NULL)    {        pTmp = pTmp->next;        pCur->next = pRev;        pRev = pCur;        pCur = pTmp;    }    return pRev;}

3.查找单向链表中倒数第k个节点

List* FindK(List *pHead, int k){    unsigned int count = GetCount(pHead);    if(k == 0 || count == 0 || count < k)        return NULL;    List *pTmp = pHead;    for(int n = 0;n < count - k;++n)    {        pTmp = pTmp->next;    }    return pTmp;}

4.查找单链表的中间节点
可以直接计算中间节点的值,也可以用两个指针,第一个指针每次走两步,第二个指针每次走一步。第一个指针走到头了,第二个指针就走到中间了。

List* MidNode(List *pHead){    unsigned int count = GetCount(pHead);    if(count == 0)        return NULL;    unsigned int mid = (count-1)/2;    List *pTmp = pHead;    for(int i = 0;i < mid;++i)    {        pTmp = pTmp->next;    }    return pTmp;}

5.从尾到头打印单链表
此题用栈来解决,可以使用STL的容器适配器stack,或者用递归。递归即是典型的栈思想。

void PrintNode(List *pHead){    if(pHead == NULL || pHead->next == NULL)        return pHead;    stack<List*> Stack;   //使用容器适配器(stack)    List *pTmp = pHead;    while(pTmp != NULL)    {        Stack.push(pTmp);        pTmp = pTmp->next;    }    while(!Stack.empty())    {        pTmp = Stack.top();        printf("%d\n",pTmp->val);        Stack.pop();    }}使用递归:void f(List *pHead){    if(pHead == NULL)        return;    else{        f(pHead->next)        printf();    }}

6.已知两个单链表各自有序,将它们合成一个新的有序的链表

List* f(List *pHead1,List *pHead2){    if(pHead1 == NULL)        return pHead2;    if(pHead2 == NULL)        return pHead1;    List *newList = NULL;    if(pHead1->val < pHead2->val)    {        newList = pHead1;        pHead1 = pHead1->next;        newList->next = NULL;    }    else    {        newList = pHead2;        pHead2 = pHead2->next;        newList->next = NULL;    }    List *pTmp = newList;    while(pHead1 != NULL && pHead2 != NULL)    {        if(pHead1 ->val < pHead2 ->val)        {            pTmp->next = pHead1;            pTmp = pHead1;            pHead1 = pHead1->next;            pTmp->next = NULL        }        else        {            pTmp->next = pHead2;            pTmp = pHead2;            pHead2 = pHead2->next;            pTmp->next = NULL        }    }    if(pHead1 != NULL)        pTmp->next = pHead1;    else if(pHead2 != NULL)        pTmp->next = pHead2;    return newList;}

7.判断一个单链表中是否有环

bool f(List *pHead){    List *pTmp1 = pHead,*pTmp2 = pHead;    while(pTmp2 != NULL && pTmp2->next != NULL)    {        pTmp1 = pTmp1->next;        pTmp2 = pTmp2->next->next;        if(pTmp1 == pTmp2)            return true;    }    return false;}

8.判断两个单链表是否相交
如果两个链表相交,那么最后一个节点肯定是两个链表共有的

boof f(List *pHead1,List *pHead2){    if(pHead1 == NULL || pHead2 == NULL)        return false;    List *pTmp1 = pHead1,*pTmp2 = pHead2;    while(pTmp1->next != NULL)        pTmp1 = pTmp1->next;    while(pTmp2->next != NULL)        pTmp2 = pTmp2->next;    return (pTmp1 == pTmp2);}

9.求两个单链表相交的第一个节点
采用栈来进行寻找,先入栈,再一个个出栈,栈顶元素不相同了,则上一个出栈的元素即为相交的节点

List* f(List *pHead1,List *pHead2){    if(pHead1 == NULL || pHead2 == NULL)        return NULL;    stack<List*> Stack1;    stack<List*> Stack2;    List *pTmp1 = pHead1,*pTmp2 = pHead2;    while(pTmp1 != NULL)    {        Stack1.push(pTmp1);        pTmp1 = pTmp1->next;    }    while(pTmp2 != NULL)    {        Stack2.push(pTmp2);        pTmp2 = pTmp2->next;    }    while(Stack1.top() == Stack2.top())    {        pTmp1 = Stack1.top();        Stack1.pop();        Stack2.pop();    }    return pTmp1;}

先求得两个链表的长度l1,l2.假设l1 > l2,用l1-l2求得差值k,然后l1向后走k步,再一起向前走,直到两节点相同

List* f(List *pHead1,List *pHead2){    if(pHead1 == NULL || pHead2 == NULL)        return NULL;    int len1 = 1,len2 = 1;    List *pTmp1 = pHead1,*pTmp2 = pHead2;    while(pTmp1->next != NULL)    {        len1++;        pTmp1 = pTmp1->next;    }    while(pTmp2->next != NULL)    {        len2++;        pTmp2 = pTmp2->next;    }    if(pTmp1 != pTmp2)        return NULL;    int k = 0;    pTmp1 = pHead1;    pTmp2 = pHead2;    if(len1 > len2)    {        k = len1 - len2;        while(--k)            pTmp1 = pTmp1->next;    }else{        k = len2 - len1;        while(--k)            pTmp2 = pTmp2->next;    }    while(pTmp1 != pTmp2)    {        pTmp1 = pTmp1->next;        pTmp2 = pTmp2->next;    }    return pTmp1;}

10.已知一个单链表中存在环,求进入环中的第一个节点

List* f(List *pHead){    if(pHead == NULL || pHead->next == NULL)        return NULL;    set<List*> hashSet;    List *pTmp = pHead;    while(!hashSet.count(pTmp))    {        hashSet.insert(pTmp);        pTmp = pTmp->next;    }    return pTmp;}

先找到相遇点。从链表头、与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇点为环入口点,也即为两个链表的第一个相同节点。

List* f(List *pHead){    List *slow = head, *fast = head;    while ( fast && fast->next )     {         slow = slow->next;         fast = fast->next->next;         if ( slow == fast )  break;    }    if (fast == NULL || fast->next == NULL)        return NULL;    slow = head;    while (slow != fast)    {         slow = slow->next;         fast = fast->next;    }    return slow;}
  1. 给出一单链表头指针pHead和一节点指针pToBeDeleted,O(1)时间复杂度删除节点pToBeDeleted
    对于删除节点,我们普通的思路就是让该节点的前一个节点指向该节点的下一个节点,这种情况需要遍历找到该节点的前一个节点,时间复杂度为O(n)。对于链表,链表中的每个节点结构都是一样的,所以我们可以把该节点的下一个节点的数据复制到该节点,然后删除下一个节点即可。要注意最后一个节点的情况,这个时候只能用常见的方法来操作,先找到前一个节点,但总体的平均时间复杂度还是O(1)。参考代码如下:
    void Delete(ListNode * pHead, ListNode * pToBeDeleted)      {          if(pToBeDeleted == NULL)              return;          if(pToBeDeleted->m_pNext != NULL)          {              pToBeDeleted->m_nKey = pToBeDeleted->m_pNext->m_nKey; // 将下一个节点的数据复制到本节点,然后删除下一个节点              ListNode * temp = pToBeDeleted->m_pNext;              pToBeDeleted->m_pNext = pToBeDeleted->m_pNext->m_pNext;              delete temp;          }          else // 要删除的是最后一个节点          {              if(pHead == pToBeDeleted) // 链表中只有一个节点的情况              {                  pHead = NULL;                  delete pToBeDeleted;              }              else              {                  ListNode * pNode = pHead;                  while(pNode->m_pNext != pToBeDeleted) // 找到倒数第二个节点                      pNode = pNode->m_pNext;                  pNode->m_pNext = NULL;                  delete pToBeDeleted;              }             }      }  
0 0