链表
来源:互联网 发布:上海张江租房 知乎 编辑:程序博客网 时间:2024/05/08 23:40
1.逆序打印LinkedList
1.从尾到头打印list的话,考虑用stack先把各节点保存起来,遍历完以后再将stack弹出打印即可
2.用递归模拟stack,每次遍历list当前节点的时候,递归调用下一个节点,直到list结尾
1: public void printReverseList(Node head) {
2: if (head == null)
3: return;
4: Node temp = head;
5: if (temp.getNext() != null) {
6: printReverseList(temp.getNext());
7: }
8: System.out.println(temp.getData());
9: }
2.在O(1)时间内删除链表中指定的节点
已给出了要删除node的指针,可以很方便地找到要删除node的下一个node,将下一个node的信息复制到当前node,再将下一个node删除,这正好相当于将当前node删除!时间复杂度是O(1),需要注意的是假设当前node是最后一个的话node->next为空,上面的思路就不行了,我们还是需要找到尾节点的上一个节点!如果所有链表只有一个节点,那么我们将head置空即可。
1: public void deleteNode(Node head, Node deleteNode) {
2: if (head == null || deleteNode == null) {
3: return;
4: }
5: Node nextNode;
6: if (deleteNode.getNext() != null) {
7: nextNode = deleteNode.getNext();
8: deleteNode.setDate(nextNode.getData());
9: deleteNode.setNext(nextNode.getNext());
10: nextNode = null;
11: } else if (deleteNode == head) {// 只有一个节点
12: head = null;
13: } else {// 删除尾节点,只能遍历一次
14: nextNode = head;
15: while (nextNode.getNext() != deleteNode)
16: nextNode = nextNode.getNext();
17: nextNode.setNext(null);
18: deleteNode = null;
19: }
20: }
3.寻找list中倒数第k个节点
思路:使用两个指针,刚开始同时指向list头,然后第二个指针p2前进k-1步,然后第一个指针p1和p2,同时前进,知道p2到达list尾,这时p1指向倒数第k个节点(如果是找中间节点,则一个每次移一步,一个每次移两步)
1: public Node find_k_reverseNode(Node head, int k) {
2: if (head == null || k < 1)
3: return null;
4: Node p1, p2;
5: p1 = p2 = head;
6: int i = 0;
7: while (p2.getNext() != null && (++i != k)) {
8: p2 = p2.getNext();
9: }
10: if (p2.getNext() == null) {// list长度小于k-1
11: return null;
12: }
13: while (p2.getNext() != null) {
14: p1 = p1.getNext();
15: p2 = p2.getNext();
16: }
17: return p1;
18: }
4.反转list
最好画画图啥的,需要注意的中间需要一些节点保存指针,要不会造成list的断裂,需要三个指针,当前指针,当前指针前一个指针,当前指针后一个指针
1: public Node reverseList(Node head) {
2: if (head == null || head.getNext() == null) {
3: return head;
4: }
5: // 一共需要三个指针,当前节点之前,当前节点,当前节点之后的节点。
6: // 这样才不会造成 调整过程中的list的断裂
7: Node preNode = null;
8: Node curNode = head;
9: Node nextNode = curNode.getNext();
10: while (nextNode != null) {
11: curNode.setNext(preNode);
12: preNode = curNode;
13: curNode = nextNode;
14: nextNode = nextNode.getNext();
15: }
16: curNode.setNext(preNode);// 这个时候curNode就是原来的尾节点
17: return curNode;
18: }
递归方式:
1: public Node reverseList(Node head) {
2: if (head == null) {
3: return null;
4: }
5: if (head.getNext() == null) {
6: return head;
7: }
8: Node node = reverseList(head.getNext());//先反转后面的链表
9: head.getNext().setNext(head);//再将当前节点设置为其后面节点的后续节点
10: head.setNext(null);
11: return node;
12: }
5.合并两个有序list
1: 递归方式:
2: public Node mergeList(Node p1, Node p2) {
3: if (p1 == null || p2 == null) {
4: return p1 == null ? p2 : p1;
5: }
6: Node result;
7: if (p1.getData() < p2.getData()) {
8: result = p1;
9: result.setpNext(mergeList(p1.getpNext(), p2));
10: } else {
11: result = p2;
12: result.setpNext(mergeList(p1, p2.getpNext()));
13: }
14: return result;
15: }
16:
17:
18: 非递归:
19: public Node mergeList(Node p1, Node p2) {
20: if (p1 == null || p2 == null) {
21: return p1 == null ? p2 : p1;
22: }
23: Node result, current;
24: if (p1.getData() < p2.getData()) {
25: result = p1;
26: p1 = p1.getpNext();
27: } else {
28: result = p2;
29: p2 = p2.getpNext();
30: }
31: current = result;
32: while (p1 != null && p2 != null) {
33: if (p1.getData() < p2.getData()) {
34: current.setpNext(p1);
35: p1 = p1.getpNext();
36: current = current.getpNext();
37: } else {
38: current.setpNext(p2);
39: p2 = p2.getpNext();
40: current = current.getpNext();
41: }
42: }
43: if (p1 != null) {
44: current.setpNext(p1);
45: }else {
46: current.setpNext(p2);
47: }
48: return result;
49: }
50:
6. 判断俩个链表是否相交
给出俩个单向链表的头指针,比如 h1,h2,判断这俩个链表是否相交。为了简化问题,我们假设俩个链表均不带环。
问题扩展:
1.如果链表可能有环列?
2.如果需要求出俩个链表相交的第一个节点列?
1: public Node isJoined(Node p1, Node p2) {
2: if (p1 == null || p2 == null) {
3: return null;
4: }
5: Node cylic1 = hasCylic(p1);
6: Node cylic2 = hasCylic(p2);
7: if (cylic1 == null && cylic2 == null) {// 都无环
8: Node h1 = p1, h2 = p2;
9: int i = 1, k = 1;
10: while (h1.getpNext() != null) {
11: i++;
12: h1 = h1.getpNext();
13: }
14: while (h2.getpNext() != null) {
15: k++;
16: h2 = h2.getpNext();
17: }
18: if (h1 != h2) {// 无交点
19: return null;
20: }
21: // 有交点
22: h1 = p1;
23: h2 = p2;
24: if (i >= k) {// p1链比p2链长
25: for (int j = 0; j < i - k; j++) {
26: h1 = h1.getpNext();
27: }
28: } else {// p2链比p1链长
29: for (int j = 0; j < i - k; j++) {
30: h2 = h2.getpNext();
31: }
32: }
33: while (h1 != h2) {
34: h1 = h1.getpNext();
35: h2 = h2.getpNext();
36: }
37: return h1;
38: } else if ((cylic1 == null && cylic2 != null)
39: || (cylic1 != null && cylic2 == null)) {// 一个有环,一个无环
40: return null;
41: }
42: // 都有环
43: Node p = cylic1.getpNext();
44: Node q = cylic2.getpNext();
45: if (p == cylic1 && q == cylic2) {// 环上都只有一个节点
46: if (p != q) {
47: return null;// 不相交
48: }
49: return p;
50: } else if ((p == cylic1 && q != cylic2) || (p != cylic1 && q == cylic2)) {
51: // 某一个环上只有一个节点,另一个不止一个节点,一定不相交
52: return null;
53: }
54: // 两个环上都不止一个节点
55: if (cylic1 == cylic2) {// 共环且入口一样。但交点可能在环上cylic1节点,也可能不在环上
56: p = p1;
57: q = p2;
58: int i = 1, k = 1;
59: while (p != cylic1) {
60: p = p.getpNext();
61: i++;
62: }
63: while (q != cylic2) {
64: q = q.getpNext();
65: k++;
66: }
67: if (i == k) {
68: return cylic1;
69: }
70: p = p1;
71: q = p2;
72: if (i >= k) {// p1链比p2链长
73: for (int j = 0; j < i - k; j++) {
74: p = p.getpNext();
75: }
76: } else {// p2链比p1链长
77: for (int j = 0; j < i - k; j++) {
78: q = q.getpNext();
79: }
80: }
81: while (p != q) {
82: p = p.getpNext();
83: q = q.getpNext();
84: }
85: return p;
86: }
87:
88: p = cylic1.getpNext();
89: q = cylic2.getpNext();
90: while (p != cylic1) {
91: if (p == cylic2) {// p1与p2共环,但是入口不一样
92: return p;
93: }
94: p = p.getpNext();
95: }
96: return null;
97: }
98:
99: // 从起点开始,一个每次走一步,一个每次走两步,有环则两个节点在某一时刻会相交
100: public Node hasCylic(Node head) {
101: Node p1 = head, p2 = head;
102: while (p2 != null && p2.getpNext() != null) {
103: p1 = p1.getpNext();
104: p2 = p2.getpNext().getpNext();
105: if (p1 == p2) {
106: return p1;
107: }
108: }
109: return null;
110: }
7. 复杂链表的复制
有一个复杂链表,其结点除了有一个 pNext 指针指向下一个结点外,还有一个pSibling指向链表中的任一结点或者 NULL。
如图所示,有A、B、C、D四个节点,大致思路是先克隆,再分离。
1: public ComplexNode clone(ComplexNode head) {
2: if (head == null) {
3: return null;
4: }
5: ComplexNode pComplexNode = head;
6: ComplexNode cloneNode;
7: do {// 复制节点
8: cloneNode = new ComplexNode();
9: cloneNode.setData(pComplexNode.getData() + 10);// 复制节点值
10: cloneNode.setpNext(pComplexNode.getpNext());// 复制节点与原节点指向相同的下一个节点
11: pComplexNode.setpNext(cloneNode);// 原节点的next指向复制节点
12: pComplexNode = cloneNode.getpNext();// 准备复制下一原节点
13: } while (pComplexNode != null);
14: pComplexNode = head;
15: do {// 复制pSinling
16: cloneNode = pComplexNode.getpNext();
17: if (pComplexNode.getpSinling() != null) {// 原节点的pSinling指向不为空
18: cloneNode.setpSinling(pComplexNode.getpSinling().getpNext());
19: // 复制节点的pSinling指向为原节点的pSinling指向的节点下一节点
20: }
21: pComplexNode = cloneNode.getpNext();
22: } while (pComplexNode != null);
23: pComplexNode = head;
24: ComplexNode newHead = pComplexNode.getpNext();
25: cloneNode = newHead;
26: do {// 断开链表
27: pComplexNode.setpNext(cloneNode.getpNext());// 原节点的pNext指向复制节点的pNext,即原始的下一节点
28: pComplexNode = pComplexNode.getpNext();// 指向原始的下一节点
29: if (pComplexNode != null) {
30: // 最末端时,pComplexNode ==null,pComplexNode.getpNext()会抛空指针异常
31: cloneNode.setpNext(pComplexNode.getpNext());// 复制节点的pNext,即复制节点的下一节点
32: } else {
33: cloneNode.setpNext(null);
34: }
35: cloneNode = cloneNode.getpNext();// 指向复制节点的下一节点
36: } while (cloneNode != null);
37: return newHead;
38: }
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- js的slice函数
- RTMP服务器的延迟,多级边缘不影响延迟,gop为最大因素
- Java基础编程体会
- bzoj1691 treap
- 初涉java
- 链表
- ios-day18-12(使用CATransition实现转场动画效果)
- 读数字练习
- python中读写中文文件小结
- 第二章作业题P51.8(输入整数a和b,如果a能被b整除,就输出算式和商,否则就输出算式,整数商和余数。)
- 计算机组成第二周:指令系统体系结构
- 黑马程序员—OC学习笔记—@property和@synthesize的五种类型运用与归纳
- 如何在发起HTTP请求时附带Cookie
- java程序初步理解