链表相关算法:

链表结点定义如下:

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:复杂链表的复制(复杂链表)

待续。。。。。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值