code总结【链表】

来源:互联网 发布:识别歌曲的软件 编辑:程序博客网 时间:2024/05/09 18:51

之前刷leetcode和剑指offer,看到很多需要用到链表的题,但没看到什么全面总结链表的文章,刚看到一篇总结链表的,很详细,特别好。

出处:http://www.cnblogs.com/byonecry/p/4458821.html

自己在此之上再进行了补充

数据结构之链表-链表实现及常用操作(C++篇)

0.摘要

  • 链表数据结构
  • 插入节点(单向链表)
  • 删除节点(单向链表)
  • 反向遍历链表
  • 找出中间节点
  • 找出倒数第k个节点
  • 翻转链表
  • 判断两个链表是否相交,并返回相交点
  • 判断链表是否有环路,获取连接点,计算环的长度
  • 二叉树和双向链表转化

1.数据结构

1.1单向链表

单向链表的节点包括:

  1. 数据域:用于存储数据元素的值。
  2. 指针域(链域):用于存储下一个结点地址或者说指向其直接后继结点的指针。

    struct Node{    int value;    Node * next;};

1.2双向链表

双向链表的节点包括:

  1. 数据域:用于存储数据元素的值。
  2. 左指针域(左链域):用于存储上一个结点地址或者说指向其直接前继结点的指针。
  3. 右指针域(右链域):用于存储下一个结点地址或者说指向其直接后继结点的指针。

    struct DNode{    int value;    DNode * left;    DNode * right;};

2.常用操作例题

2.1插入节点(单向链表)

//p节点后插入值为i的节点void insertNode(Node *p, int i){    Node* node = new Node;    node->value = i;    node->next = p->next;    p->next = node;}

2.2删除节点(单向链表)

当需要删除一个节点p时,只需要将p的前一个节点的next赋为p->next,但是由于是单向的,只知道p,无法知道p前一个节点,所以需要转换思路。将p下一个的节点覆盖到p节点即可,这样就等效于将p删除了。

void deleteNode(Node *p){    p->value = p->next->value;    p->next = p->next->next;}

2.3反向遍历链表

法一:反向遍历链表就类似于事先遍历的节点后输出,即“先进后出”,那么可以将链表遍历存放于栈中,其后遍历栈依次弹出栈节点,达到反向遍历效果。

//1.借助stackvoid printLinkedListReversinglyByStack(Node *head){    stack<Node* > nodesStack;    Node* pNode = head;    //遍历链表    while (pNode != NULL) {        nodesStack.push(pNode);        pNode = pNode->next;    }    while (!nodesStack.empty()) {        pNode=nodesStack.top();        printf("%d\t", pNode->value);        nodesStack.pop();    }}//2.递归void printLinkedListReversinglyRecursively(Node *head){    if (head!=NULL) {        if (head->next!=NULL) {            printLinkedListReversinglyRecursively(head->next);        }        printf("%d\t", head->value);    }}//3.借助vector
vector<int> printListFromTailToHead(ListNode* head) {
        vector<int> value;
        if(head!=NULL){
            value.insert(value.begin(),head->val);
            while(head->next!=NULL){
                value.insert(value.begin(),head->next->val);
                head=head->next;
            }
        }
        return value;
    }

2.4找出中间节点

用slow和fast指针标记,slow每次走一步,fast每次走两步,当fast到尾节点时,slow就相当于总长度的一半,即在中间节点。

//找出中间节点Node* findMidNode(Node* head){    Node* slow = head;    Node* fast = head;    while (fast->next != 0&&fast->next->next!=0) {        slow = slow->next;        fast = fast->next->next;    }    return slow;}

2.5找出倒数第k个节点

用slow和fast指针标记,fast指针事先走k步,然后slow和fast同时走,当fast到达末节点时,slow在fast的前k个节点,即为倒数第k个节点。

ListNode* FindKthFromTail(ListNode* pListHead,int k)  {      if (pListHead == NULL || k == 0) //防止空的链表  和 k值 等于 0 的情况      {          return NULL;      }      ListNode* pAhead = pListHead;      ListNode* pBehind = NULL;      for (int i = 0; i < k-1; i++)      {          if (pAhead->m_pNext != NULL)          {              pAhead = pAhead->m_pNext;          }          else          {              return NULL;          }      }      pBehind = pListHead;      while(pAhead->m_pNext != NULL)      {                    pAhead  = pAhead->m_pNext;          pBehind = pBehind->m_pNext;      }        return pBehind;    } 

2.6翻转链表

题意即为将链表反过来,即,原本为p1-p2-p3翻转为p3-p2-p1。读者需自行画图体会指针操作。

网上有个很好的带图解释,链接如下:

       http://blog.csdn.net/feliciafay/article/details/6841115

2.7判断两个链表是否相交,并返回相交点

如果两个链表相交,其形状必为y形,而不可以能为x形,即两条链表必有相同的尾节点。首先,计算得到两个链表的长度:m,n,求得两个链表长度之差distance=|m-n|,让较长得那个链表事先走distance步,这样,若是链表相交得话,二者指针必相撞,相撞点即为相交点

Node* findCrosspoint(Node* l1, Node* l2){    int m = getLinkedListLength(l1);    int n = getLinkedListLength(l2);    int distance=0;    Node *temp1= l1;    Node *temp2= l2;    if (m>n) {        distance = m - n;        while (distance>0) {            distance--;            temp1=temp1->next;        }    } else{        distance = n - m;        while (distance>0) {            distance--;            temp2 = temp2->next;        }    }    while(temp1!=temp2&&temp1->next!=NULL&&temp2->next!=NULL){        temp1=temp1->next;        temp2=temp2->next;    }    if(temp1 == temp2){        return temp1;    }    return 0;}

2.8判断链表是否有环路,获取连接点,计算环的长度

此题很有意思,具体详细请参考:http://www.cnblogs.com/xudong-bupt/p/3667729.html
判断是否含有环:slow和fast,slow指针每次走一步,fast指针每次走两步,若是链表有环,fast必能追上slow(相撞),若fast走到NULL,则不含有环。

//判断是否含有环bool containLoop(Node* head){    if (head==NULL) {        return false;    }    Node* slow = head;    Node* fast = head;    while (slow!=fast&&fast->next!=NULL) {        slow = slow->next;        fast = fast->next->next;    }    if (fast==NULL) {        return false;    }    return true;}

判断环的长度:在相撞点处,slow和fast继续走,当再次相撞时,slow走了length步,fast走了2*length步,length即为环得长度。

//获得环的长度int getLoopLength(Node* head){    if (head==NULL) {        return 0;    }    Node* slow = head;    Node* fast = head;    while (slow!=fast&&fast->next!=NULL) {        slow = slow->next;        fast = fast->next->next;    }    if (fast==NULL) {        return 0;    }    //slow和fast首次相遇后,slow和fast继续走    //再次相遇时,即slow走了一圈,fast走了两圈    int length = 0;    while (slow!=fast) {        length++;        slow = slow->next;        fast = fast->next->next;    }    return length;}

环得连接点:slow和fast第一次碰撞点到环的连接点的距离=头指针到环的连接点的距离,此式可以证明,详见上面链接。

//获得环的连接点Node* getJoinpoit(Node* head){    if (head==NULL) {        return NULL;    }    Node* slow = head;    Node* fast = head;    while (slow!=fast&&fast->next!=NULL) {        slow = slow->next;        fast = fast->next->next;    }    if (fast==NULL) {        return NULL;    }    Node* fromhead = head;    Node* fromcrashpoint = slow;    while (fromcrashpoint!=fromhead) {        fromhead = fromhead->next;        fromcrashpoint = fromcrashpoint->next;    }    return fromhead;}

2.9二叉树和双向链表转化

二叉树和双向链表转化指的是,二叉树节点结构和双向链表的结构想类似,只不过二叉树节点的节点存储的两个指针为左右子数,而双向链表存储的是前后节点。题意为将二叉树的某种遍历转化为链表存储。此题很明显该用递归,读者可以画图体会一下指针变化。

二叉树节点或双向链表节点定义:

struct BinaryTreeNode{    int value;    BinaryTreeNode* left;    BinaryTreeNode* right;};

二叉树的中序遍历转换为双向链表

BinaryTreeNode* convertNode(BinaryTreeNode* pNode, BinaryTreeNode** pLastNodeInLast){    if (pNode == NULL) {        return NULL;    }    BinaryTreeNode *pCurrent = pNode;    if (pCurrent->left != NULL) {        convertNode(pCurrent->left, pLastNodeInLast);    }    pCurrent->left = *pLastNodeInLast;    if (*pLastNodeInLast != NULL) {        (*pLastNodeInLast)->right=pCurrent;    }    *pLastNodeInLast = pCurrent;    if (pCurrent->right != NULL) {        convertNode(pCurrent->right, pLastNodeInLast);    }    return NULL;}BinaryTreeNode* convertBTToDLL(BinaryTreeNode* root){    BinaryTreeNode *pLastNodeInLast = NULL;    convertNode(root, &pLastNodeInLast);    BinaryTreeNode *pHeadOfList = pLastNodeInLast;    while (pHeadOfList != NULL && pHeadOfList->left != NULL) {        pHeadOfList = pHeadOfList->left;    }    return pHeadOfList;}

0 0
原创粉丝点击