code总结【链表】
来源:互联网 发布:识别歌曲的软件 编辑:程序博客网 时间:2024/05/09 18:51
之前刷leetcode和剑指offer,看到很多需要用到链表的题,但没看到什么全面总结链表的文章,刚看到一篇总结链表的,很详细,特别好。
出处:http://www.cnblogs.com/byonecry/p/4458821.html
自己在此之上再进行了补充
数据结构之链表-链表实现及常用操作(C++篇)
0.摘要
- 链表数据结构
- 插入节点(单向链表)
- 删除节点(单向链表)
- 反向遍历链表
- 找出中间节点
- 找出倒数第k个节点
- 翻转链表
- 判断两个链表是否相交,并返回相交点
- 判断链表是否有环路,获取连接点,计算环的长度
- 二叉树和双向链表转化
1.数据结构
1.1单向链表
单向链表的节点包括:
- 数据域:用于存储数据元素的值。
指针域(链域):用于存储下一个结点地址或者说指向其直接后继结点的指针。
struct Node{ int value; Node * next;};
1.2双向链表
双向链表的节点包括:
- 数据域:用于存储数据元素的值。
- 左指针域(左链域):用于存储上一个结点地址或者说指向其直接前继结点的指针。
右指针域(右链域):用于存储下一个结点地址或者说指向其直接后继结点的指针。
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。读者需自行画图体会指针操作。
网上有个很好的带图解释,链接如下:
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;}
- code总结【链表】
- 常用T-Code总结
- Mageno常用Code总结
- Code Retreat总结
- Keil code Banking总结
- [个人总结]Code Review
- Code Review 总结一
- Clean Code学习总结
- Clean Code 阅读总结
- code view case 总结
- 日常code技巧总结
- Code Review简单总结
- JTA 个人总结Code例子
- html - 常用键code总结
- FI 常用T-code总结
- 写出好的code总结
- Code Review 之后的总结
- Cracking the code interview总结
- HTML5 input改变默认样式
- 文件上传
- Inno Setup 注册表启动项 修改注册表
- BigDL 介绍
- Spring Mvc执行过程
- code总结【链表】
- python学习笔记-4.2列表和切片
- [leetcode]-537 Complex Number Multiplication
- 5.Selenium2 自动化测试实战-基于Python语言-控制浏览器后退、前进
- Windows下的高精度定时器实现及精确时刻获取
- 十、UI-Grid CellClass
- Android 混淆详解
- bzoj1143: [CTSC2008]祭祀river
- Neo4j介绍与使用