链表
2016-05-02 16:25
363 查看
链表的数据结构体:
带头结点的链表的创建:
删除第n个结点:
链表输出:
无头结点的反转:设置三个指针,从前往后扫。
带头结点的反转:设置三个指针,从前往后扫。
反转中间某段:
Leetcode25. Reverse Nodes in k-Group
另起一个函数反转中间某段,注意指针为引用型。翻转的时候,依然需要三个指针。
——————————————————————————————————————
测试:
其他
问题1:删除不知头结点链表的某个节点
如果单向链表不知道头节点,一个指针指向其中的一个节点,问如何删除这个指针指向的节点?
思想为:把这个节点的下一个节点的值复制给该节点,然后删除下一个节点即可。
问题2:怎么判断链表中是否有环?
思想为:设置两个指针,一个步长为1,另一个步长为2,依次后移,如果相遇且都不为空,则有环。
问题3:如果一个单向链表,其中有环,怎么找出这个链表循环部分的第一个节点?
思想为:假设该节点在x位置处,假设步长为1的指针和步长为2的指针相遇在x处,
那么当一个指针再从头节点处以步长1递进时,另一指针从x点以步长1递进时,两个指针就会在循环开始处相遇。
简单证明:显然步长为2的指针多跑了k*循环长,而步长2跑的路程是步长1的两倍,则步长1跑了k*循环长。那么头节点和x节点离循环开始处距离相同。
问题4:如何查找链表中倒数第k个节点?
思想为:两个指向头结点的指针,一个先向后移动k位,然后两个同时向后面移动直到一个节点到达链尾,前面一个指针的位置就是了。
问题5:两个有序链表如何合并?
思想为:设两链表为La,Lb,设三指针pa,pb,pc。其中pa、pb指向两链表当前比较插入的结点,pc指向合并的链表的最后一个结点(初始状态可直接将其中一个链表 La 的头结点作为合并链表的尾结点)。
问题6:编程序判断两个链表是否相交。
如何知道两个单链表(无环)是否相交
如果两个单链表(无环)相交,如何知道它们相交的第一个节点是什么
如何知道两个单链表(有环)是否相交
如果两个单链表(有环)相交,如何知道它们相交的第一个节点是什么
答案
这个问题的精彩解说请参见《编程之美》一书之《编程判断两个链表是否相交》,这里就不写了,该书的pdf文档在网上很好下。
文章后面给了两个扩展问题:
(1)如果链表可能有环,如何做判断?
思想为:首先应该明白,只有一个链表有环的情况下是不会相交的,只有都有环或者都没有环的情况下才可能相交,都没有环的情况下最简便的方法就是判断链尾是否相交即可;都有环的情况下,分别找到环上的任一点,一个不动,另一个步进,即可判断是否相交。
(2)如何求相交链表的第一个节点?应该为单链表情况
思想为:方法一是先把任一个链表连成环,即从表尾接到表头,按照问题4的解法;方法二是计算两个链表的长度,而两个链表是按照尾部对齐的,那么从短链表的第一个位置从长链表的第长度差+1的位置依次比较指针值,相等的位置即是。
关于链表的排序
O(n^2)算法从前往后扫,交换结点内的值。
O(nlogn)算法,O(1)插入删除(排序的时候,比参考点小,直接插入头节点前,否则插入尾节点后)。
struct node{ int data; node* next; node(int data = 0):data(data), next(0){} };
带头结点的链表的创建:
node* create(int n){//带头结点的链表的创建 node* head = new node(), *p = head; for(int i = 1; i <= n; i++){ p->next = new node(i); p = p->next; } return head; }
删除第n个结点:
void del(node* head, int n){ node* p = head, *q = head->next; while(--n){ p = p->next; q = q->next; } p->next = q->next; free(q); }
链表输出:
void show(node* head){ node* p = head->next; while(p){ printf("%d ", p->data); p = p->next; } puts(""); }
无头结点的反转:设置三个指针,从前往后扫。
void reverse(node*& head){//无头结点的反转 if(head == NULL||head->next == NULL) return ; node *p = head, *q = p->next, *ptr; while(q != NULL){ ptr = q->next; q->next = p; p = q; q = ptr; } head->next = NULL; head = p; return ; }
带头结点的反转:设置三个指针,从前往后扫。
void reverse2(node*& head){//带头结点的反转 if(head == NULL||head->next == NULL) return ; node *p = head->next, *q = p->next, *ptr; while(q != NULL){ ptr = q->next; q->next = p; p = q; q = ptr; } head->next->next = NULL; head->next = p; return ; }
反转中间某段:
Leetcode25. Reverse Nodes in k-Group
另起一个函数反转中间某段,注意指针为引用型。翻转的时候,依然需要三个指针。
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: void inv(ListNode *&start, ListNode *&end){//reverse the node from start to end ListNode *p = start, *m = p->next, *q = m->next; start->next = end->next; while(m != end){ m->next = p; p = m; m = q; q = q->next; } m->next = p; swap(start, end); } ListNode* reverseKGroup(ListNode* head, int k) { if(k < 2) return head; ListNode *p1 = head, *p2 = NULL; for(int i = 1; i < k&&p1 != NULL; i++) p1 = p1->next; if(p1 == NULL) return head; p2 = p1->next; inv(head, p1); while(true){ p2 = p1->next; for(int i = 1; i < k&&p2 != NULL; i++) p2 = p2->next; if(p2 == NULL) return head; inv(p1->next, p2); p1 = p2; } } };
——————————————————————————————————————
测试:
int main(){ node* head = create(10); show(head); del(head, 5); show(head); reverse2(head); show(head); return 0; }
其他
问题1:删除不知头结点链表的某个节点
如果单向链表不知道头节点,一个指针指向其中的一个节点,问如何删除这个指针指向的节点?
思想为:把这个节点的下一个节点的值复制给该节点,然后删除下一个节点即可。
问题2:怎么判断链表中是否有环?
思想为:设置两个指针,一个步长为1,另一个步长为2,依次后移,如果相遇且都不为空,则有环。
问题3:如果一个单向链表,其中有环,怎么找出这个链表循环部分的第一个节点?
思想为:假设该节点在x位置处,假设步长为1的指针和步长为2的指针相遇在x处,
那么当一个指针再从头节点处以步长1递进时,另一指针从x点以步长1递进时,两个指针就会在循环开始处相遇。
简单证明:显然步长为2的指针多跑了k*循环长,而步长2跑的路程是步长1的两倍,则步长1跑了k*循环长。那么头节点和x节点离循环开始处距离相同。
问题4:如何查找链表中倒数第k个节点?
思想为:两个指向头结点的指针,一个先向后移动k位,然后两个同时向后面移动直到一个节点到达链尾,前面一个指针的位置就是了。
问题5:两个有序链表如何合并?
思想为:设两链表为La,Lb,设三指针pa,pb,pc。其中pa、pb指向两链表当前比较插入的结点,pc指向合并的链表的最后一个结点(初始状态可直接将其中一个链表 La 的头结点作为合并链表的尾结点)。
问题6:编程序判断两个链表是否相交。
如何知道两个单链表(无环)是否相交
如果两个单链表(无环)相交,如何知道它们相交的第一个节点是什么
如何知道两个单链表(有环)是否相交
如果两个单链表(有环)相交,如何知道它们相交的第一个节点是什么
答案
这个问题的精彩解说请参见《编程之美》一书之《编程判断两个链表是否相交》,这里就不写了,该书的pdf文档在网上很好下。
文章后面给了两个扩展问题:
(1)如果链表可能有环,如何做判断?
思想为:首先应该明白,只有一个链表有环的情况下是不会相交的,只有都有环或者都没有环的情况下才可能相交,都没有环的情况下最简便的方法就是判断链尾是否相交即可;都有环的情况下,分别找到环上的任一点,一个不动,另一个步进,即可判断是否相交。
(2)如何求相交链表的第一个节点?应该为单链表情况
思想为:方法一是先把任一个链表连成环,即从表尾接到表头,按照问题4的解法;方法二是计算两个链表的长度,而两个链表是按照尾部对齐的,那么从短链表的第一个位置从长链表的第长度差+1的位置依次比较指针值,相等的位置即是。
关于链表的排序
O(n^2)算法从前往后扫,交换结点内的值。
O(nlogn)算法,O(1)插入删除(排序的时候,比参考点小,直接插入头节点前,否则插入尾节点后)。
相关文章推荐
- css三列布局,两侧宽度固定,中间宽度自由伸缩
- 进程同步(四)—— 消息队列
- 【技巧】修改windows10在高分屏下的应用的dpi
- 第十一周项目4.1 教师干部信息
- CentOS 6.0 图形(图解)安装教程
- Lucene 工作原理 之倒排索引
- CS231n Convolutional Neural Networks for Visual Recognition 课程翻译(一)
- 网站优化排名到首页到底要多久?
- Uva 514 Rails(栈应用)
- css三列布局,左边两个div固定,最右边宽度自适应
- AsyncTask的基本用法
- system.in的用法,system.out的用法。
- Hibernate持久化方法save和persist的区别
- gzip压缩笔记
- Java日期类
- 用SoapUI 测试Web Service
- Edit Distance
- 聪明的kk --- 搜索超时
- HDU 2444 The Accomodation of Students(判断是否是二分图及求最大匹配)
- [leetcode] Wildcard Matching 通配符匹配