6-4 链表拼接 (20分)_数据结构之链表
在面试过程中,数据结构和算法基本上算是研发类岗位必考的部分,而链表基本上又是数据结构中相对容易掌握、而且容易出题的部分,因此我们先整理一下链表部分的经典题目。
(声明:以下所有程序都是用java编写)
首先,我们来定义一个链表的数据结构,如下:
View Code 1 public class Link {2 private int value;3 private Link next;4 public void set_Value(int m_Value) {5 this.value = m_Value;6 }7 public int get_Value() {8 return value;9 }
10 public void set_Next(Link m_Next) {11 this.next = m_Next;
12 }
13 public Link get_Next() {14 return next;
15 }
16 }
有了这个数据结构后,我们需要一个方法来生成和输出链表,其中链表中每个元素的值采用的是随机数。
生成链表的代码如下:
View Code 1 public static Link init(int count, int maxValue)2 {3 Link list = new Link();4 Link temp = list;5 Random r = new Random();6 temp.set_Value(Integer.MIN_VALUE);7 for (int i = 0; i < count; i++)8 {9 Link node = new Link();
10 node.set_Value(r.nextInt(maxValue));
11 temp.set_Next(node);
12 temp=node;
13 }
14 temp.set_Next(null);
15 return list;
16 }
17
18 public static Link init(int count)
19 {20 return init(count, Integer.MAX_VALUE);
21 }
对于链表的头结点,我们是不存储任何信息的,因此将其值设置为Integer.MIN_VALUE。我们重载了生成链表的方法。
下面是打印链表信息的方法:
View Code 1 public static void printList(Link list)2 {3 if (list == null || list.get_Next() == null)4 {5 System.out.println("The list is null or empty.");6 return;7 }8 Link temp = list.get_Next();9 StringBuffer sb = new StringBuffer();
10 while(temp != null)
11 {12 sb.append(temp.get_Value() + "->");
13 temp=temp.get_Next();
14 }
15 System.out.println(sb.substring(0, sb.length() - 2));
16 }
好了,有了以上这些基础的方法, 我们就可以深入探讨链表相关的面试题了。
- 链表反转
思路:有两种方法可以实现链表反转,第一种是直接循环每个元素,修改它的Next属性;另一种是采取递归的方式。
首先来看直接循环的方式:
View Code 1 public static Link Reverve(Link list)2 {3 if (list == null || list.get_Next() == null || list.get_Next().get_Next() == null)4 {5 System.out.println("list is null or just contains 1 element, so do not need to reverve.");6 return list;7 } 8 Link current = list.get_Next();9 Link next = current.get_Next();
10 current.set_Next(null);
11 while(next != null)
12 {13 Link temp = next.get_Next();
14 next.set_Next(current);
15 current = next;
16 next = temp;
17 }
18 list.set_Next(current);
19
20 return list;
21 }
然后是递归方式:
View Code 1 public static Link RecursiveReverse(Link list)2 {3 if (list == null || list.get_Next() == null || list.get_Next().get_Next() == null)4 {5 System.out.println("list is null or just contains 1 element, so do not need to reverve.");6 return list;7 }8 9 list.set_Next(Recursive(list.get_Next()));
10
11 return list;
12 }
13
14
15 private static Link Recursive(Link list)
16 {17 if (list.get_Next() == null)
18 {19 return list;
20 }
21 Link temp = Recursive(list.get_Next());
22 list.get_Next().set_Next(list);
23 list.set_Next(null);
24
25 return temp;
26
输出指定位置的元素(倒数第N个元素)
思路:采用两个游标来遍历链表,第1个游标先走N步,然后两个游标同时前进,当第一个游标到最后时,第二个游标就是想要的元素。
View Code 1 public static Link find(Link list, int rPos)2 {3 if (list == null || list.get_Next() == null)4 {5 return null;6 }7 int i = 1;8 Link first = list.get_Next();9 Link second = list.get_Next();
10 while(true)
11 {12 if (i==rPos || first == null) break;
13 first = first.get_Next();
14 i++;
15 }
16 if (first == null)
17 {18 System.out.println("The length of list is less than " + rPos + ".");
19 return null;
20 }
21 while(first.get_Next() != null)
22 {23 first = first.get_Next();
24 second = second.get_Next();
25 }
26
27 return second;
28 }
删除指定节点
思路:可以分情况讨论,如果指定节点不是尾节点,那么可以采用取巧的方式,将指定节点的值修改为下一个节点的值,将指定节点的Next属性设置为Next.Next;但如果指定节点为尾节点,那么只能是从头开始遍历。
View Code 1 public static void delete(Link list, Link element)2 {3 if (element.get_Next() != null)4 {5 element.set_Value(element.get_Next().get_Value());6 element.set_Next(element.get_Next().get_Next());7 }8 else9 {10 Link current = list.get_Next();
11 while(current.get_Next() != element)
12 {13 current = current.get_Next();
14 }
15 current.set_Next(null);
16 }
17 }
删除重复节点
思路:采用hashtable来存取链表中的元素,遍历链表,当指定节点的元素在hashtable中已经存在,那么删除该节点。
View Code 1 public static void removeDuplicate(Link list)2 {3 if (list == null || list.get_Next() == null || list.get_Next().get_Next() == null) return;4 Hashtable table = new Hashtable();5 Link cur = list.get_Next();6 Link next = cur.get_Next();7 table.put(cur.get_Value(), 1);8 while(next != null)9 {10 if (table.containsKey(next.get_Value()))
11 {12 cur.set_Next(next.get_Next());
13 next = next.get_Next();
14 }
15 else
16 {17 table.put(next.get_Value(), 1);
18 cur= next;
19 next = next.get_Next();
20 }
21
22 }
23 }
寻找链表中间节点
思路:采用两个游标的方式,第一个游标每次前进两步,第二个游标每次前进一步,当第一个游标到最后时,第二个游标就是中间位置。需要注意的是,如果链表元素的个数是偶数,那么中间元素应该是两个。
View Code 1 public static void findMiddleElement(Link list)2 {3 if (list == null || list.get_Next() == null) return;4 System.out.println("The Middle element is:");5 if (list.get_Next().get_Next() == null)6 {7 System.out.println(list.get_Next().get_Value());8 }9 Link fast = list.get_Next();
10 Link slow = list.get_Next();
11 while(fast.get_Next() != null && fast.get_Next().get_Next() != null)
12 {13 fast = fast.get_Next().get_Next();
14 slow = slow.get_Next();
15 }
16
17 if (fast != null && fast.get_Next() == null)
18 {19 System.out.println(slow.get_Value());
20 }
21 else
22 {23 System.out.println(slow.get_Value());
24 System.out.println(slow.get_Next().get_Value());
25 }
26 }
链表元素排序
思路:链表元素排序,有两种方式,一种是链表元素本身的排序,一种是链表元素值得排序。第二种方式更简单、灵活一些。
View Code 1 public static void Sort(Link list)2 {3 if (list == null || list.get_Next() == null || list.get_Next().get_Next() == null)4 {5 return;6 }7 Link current = list.get_Next();8 Link next = current.get_Next();9 while(current.get_Next() != null)
10 {11 while(next != null)
12 {13 if (current.get_Value() > next.get_Value())
14 {15 int temp = current.get_Value();
16 current.set_Value(next.get_Value());
17 next.set_Value(temp);
18 }
19 next = next.get_Next();
20 }
21 current = current.get_Next();
22 next = current.get_Next();
23 }
24 }
判断链表是否有环,如果有,找出环上的第一个节点
思路:可以采用两个游标的方式判断链表是否有环,一个游标跑得快,一个游标跑得慢。当跑得快的游标追上跑得慢的游标时,说明有环;当跑得快的游标跑到尾节点时,说明无环。
至于如何找出换上第一个节点,可以分两步,首先确定环上的某个节点,计算头结点到该节点的距离以及该节点在环上循环一次的距离,然后建立两个游标,分别指向头结点和环上的节点,并将距离平摊(哪个距离大,先移动哪个游标,直至两个距离相等),最后同时移动两个游标,碰到的第一个相同元素,就是环中的第一个节点。
View Code 1 public static Link getLoopStartNode(Link list)2 {3 if (list == null || list.get_Next() == null || list.get_Next().get_Next() == null)4 {5 return null;6 }7 int m = 1, n = 1;8 Link fast = list.get_Next();9 Link slow = list.get_Next();
10 while(fast != null && fast.get_Next() != null)
11 {12 fast = fast.get_Next().get_Next();
13 slow = slow.get_Next();
14 if (fast == slow) break;
15 m++;
16 }
17 if (fast != slow)
18 {19 return null;
20 }
21 Link temp = fast;
22 while(temp.get_Next() != fast)
23 {24 temp = temp.get_Next();
25 n++;
26 }
27 Link node1 = list.get_Next();
28 Link node2 = fast;
29 if (m < n)
30 {31 for (int i = 0; i < n - m; i++)
32 {33 node2 = node2.get_Next();
34 }
35 }
36 if (m > n)
37 {38 for (int i = 0; i < m - n; i++)
39 {40 node1 = node1.get_Next();
41 }
42 }
43 while(true)
44 {45 if (node1 == node2)
46 {47 break;
48 }
49 node1 = node1.get_Next();
50 node2 = node2.get_Next();
51 }
52
53 return node1;
54
55 }
判断两个链表是否相交
思路:判断两个链表的尾节点是否相同,如果相同,一定相交
View Code 1 public static boolean isJoint(Link list1, Link list2)2 {3 if (list1 == null || list2 == null || list1.get_Next() == null || list2.get_Next() == null)4 {5 return false;6 }7 Link node1 = list1;8 Link node2 = list2;9 while(node1.get_Next() != null)
10 {11 node1 = node1.get_Next();
12 }
13 while(node2.get_Next() != null)
14 {15 node2 = node2.get_Next();
16 }
17
18 return node1 == node2;
19 }
合并两个有序链表
思路:新建一个链表,然后同时遍历两个有序链表,比较其大小,将元素较小的链表向前移动,直至某一个链表元素为空。然后将非空链表上的所有元素追加到新建链表中。
View Code 1 public static Link merge(Link list1, Link list2)2 {3 Link list = new Link();4 list.set_Value(Integer.MIN_VALUE);5 Link current1 = list1.get_Next();6 Link current2 = list2.get_Next();7 Link current = list;8 while(current1 != null && current2 != null)9 {10 Link temp = new Link();
11 if (current1.get_Value() > current2.get_Value())
12 {13 temp.set_Value(current2.get_Value());
14 current2 = current2.get_Next();
15 }
16 else
17 {18 temp.set_Value(current1.get_Value());
19 current1 = current1.get_Next();
20 }
21 current.set_Next(temp);
22 current = temp;
23 }
24 if (current1 != null)
25 {26 while(current1 != null)
27 {28 Link temp = new Link();
29 temp.set_Value(current1.get_Value());
30 current.set_Next(temp);
31 current = temp;
32 current1 = current1.get_Next();
33 }
34 }
35
36 if (current2 != null)
37 {38 while(current2 != null)
39 {40 Link temp = new Link();
41 temp.set_Value(current2.get_Value());
42 current.set_Next(temp);
43 current = temp;
44 current2 = current2.get_Next();
45 }
46 }
47
48 current.set_Next(null);
49
50 return list;
51 }
交换链表中任意两个元素(非头结点)
思路:首先需要保存两个元素的pre节点和next节点,然后分别对pre节点和next节点的Next属性重新赋值。需要注意的是,当两个元素师相邻元素时,需要特殊处理,否则会将链表陷入死循环。
View Code 1 public static void swap(Link list, Link element1, Link element2)2 {3 if (list == null || list.get_Next() == null || list.get_Next().get_Next() == null || 4 element1 == null || element2 == null || element1 == element2) 5 return;6 7 Link pre1 = null, pre2 = null, next1 = null, next2 = null;8 Link cur1=element1, cur2=element2;9 Link temp = list.get_Next();
10 boolean bFound1 = false;
11 boolean bFound2 = false;
12 while(temp != null)
13 {14 if(temp.get_Next() == cur1)
15 {16 pre1=temp;
17 next1 = temp.get_Next().get_Next();
18 bFound1 = true;
19 }
20 if (temp.get_Next() == cur2)
21 {22 pre2 = temp;
23 next2 = temp.get_Next().get_Next();
24 bFound2=true;
25 }
26 if (bFound1 && bFound2) break;
27 temp = temp.get_Next();
28 }
29
30 if (cur1.get_Next() == cur2)
31 {32 temp = cur2.get_Next();
33 pre1.set_Next(cur2);
34 cur2.set_Next(cur1);
35 cur1.set_Next(temp);
36 }
37 else if (cur2.get_Next() == cur1)
38 {39 temp = cur1.get_Next();
40 pre2.set_Next(cur1);
41 cur1.set_Next(cur2);
42 cur2.set_Next(temp);
43 }
44 else
45 {46 pre1.set_Next(cur2);
47 cur1.set_Next(next2);
48 pre2.set_Next(cur1);
49 cur2.set_Next(next1);
50 }
51 }
这里,还有另外一种取巧的方法,就是直接交换两个元素的值,而不需要修改引用。
View Code 1 public static void swapValue(Link list, Link element1, Link element2)2 {3 if (element1 == null || element2 == null)4 {5 return;6 }7 int temp = element1.get_Value();8 element1.set_Value(element2.get_Value());9 element2.set_Value(temp);
10 }
不过,这种方式,应该不是面试官所希望看到的。
学习资料分享交流群:1093776732 入群有全套学习视频资料电子书免费赠送!
参考资料:
什么是链表及原理_数据结构之链表精讲_嵌入式开发工程师www.makeru.com.cn
链表的反转_数据结构之链表精讲_嵌入式开发工程师www.makeru.com.cn
单链表实现-链表删除_数据结构之链表精讲_嵌入式开发工程师www.makeru.com.cn
循环链表及线性表的应用_循环链表及线性表的应用_嵌入式开发工程师www.makeru.com.cn
6-4 链表拼接 (20分)_数据结构之链表相关推荐
- 6-4 链表拼接 (20分)_青岛喷绘制作公司不愿透露的喷绘布拼接与安装技巧,建议收藏...
当我们走在大街上随时都能看到各种精美的大型户外喷绘广告,精美的画面很具有吸引力. 青岛喷绘制作公司 0532-80796756 那么大的画面,而设备是有限的,通常大型点设备最宽是5米的,其它3米多为主 ...
- 数据结构之链表及其Java实现_数据结构之链表及其Java实现
数据的存储一般分线性存储结构和链式存储结构两种.前者是一种顺序的存储方式,在内存中用一块连续的内存空间存储数据,即逻辑上相连的物理位置相邻,比较常见的就是数组:后者是一种链式存储方式,不保证顺序性,逻 ...
- 2-2 学生成绩链表处理 (20 分)
2-2 学生成绩链表处理 (20 分) 本题要求实现两个函数,一个将输入的学生成绩组织成单向链表:另一个将成绩低于某分数线的学生结点从链表中删除. 函数接口定义: struct stud_node * ...
- 6-4 学生成绩链表处理 (20分) 本题要求实现两个函数,一个将输入的学生成绩组织成单向链表;另一个将成绩低于某分数线的学生结点从链表中删除。 函数接口定义: ```cpp struct stu
6-4 学生成绩链表处理 (20分) 本题要求实现两个函数,一个将输入的学生成绩组织成单向链表:另一个将成绩低于某分数线的学生结点从链表中删除. 函数接口定义: struct stud_node *c ...
- 【2019全国职业技能大赛大数据技术】任务四:14-数据可视化(20分_题目+答案<图片+分值>)
[任务说明] 任务四 : 数据可视化 (20 分 ) 本任务中 所需要 的原始数据四 存放于任务四 MySQL 的 的 project_hotels 数据库 和 计算机 桌面/H3CU_hotel/d ...
- java城市链表_数据结构城市链表 1. 城市链表
[问题描述]将若干城市的信息 联合开发网 - pudn.com...
数据结构城市链表 所属分类:文章/文档 开发工具:Java 文件大小:174KB 下载次数:7 上传日期:2017-12-18 18:37:53 上 传 者:叁佰 说明: 1. 城市链表 [问题描述 ...
- c语言将一个已知头结点的单链表逆序_C语言数据结构实现链表逆序并输出
C语言数据结构实现链表逆序并输出 将一个链表逆序并输出.我用了两种方法来实现,第一种是借助了一个新的空链表:第二种是在原来链表的基础上直接实现逆序. 实例代码: 头文件: #include #incl ...
- PTA: 6-4建立学生信息链表(20分)
大一下半期数据结构 数据结构题目集 pta:建立学生信息链表 本题要求实现一个将输入的学生成绩组织成单向链表的简单函数. 函数接口定义: void input(); 该函数利用scanf从输入中获取学 ...
- access表怎么生成表结构_数据结构——单链表讲解
单链表 单链表的创建分为头插入法和尾插入法两种,两者并无本质上的不同,都是利用指针指向下一个结点元素的方式进行逐个创建,只不过使用头插入法最终得到的结果是逆序的. 1.单链表概念&设计 单链表 ...
最新文章
- 修改Idea默认的全局设置,如Maven等
- python数据结构推荐书-腾讯十年Python开发老司机推荐的入门书籍,你确定不看吗?...
- 找不到网卡eth0的解决方法
- 文件上传优化CommonsMultipartResolver
- python编程口诀_科学网—Python编程技巧汇总 - 高关胤的博文
- python pip本地安装包_python-pip install 安装包
- 名校博士生被电信诈骗10多万,却被嘲“博士也会被骗书白读了”,学校发声!...
- linux su root 免密码,Ubuntu 18.04.2切换到root用户的三种方式及设置免密码操作
- JAVA原码反码补码
- LED —— 发光二极管
- 平均聚类系数_聚类方法排除CPU用量误报警
- 富士驱动器ALPHA5手动JOG运行操作
- 仿今日头条项目——个人中心
- 驱动安装时数字签名无效
- 2022最新 B站PC端下载视频方法
- VCL界面控件DevExpress VCL全新发布v21.1.6
- 蓝色理想的flex教材不能在flex Development做不能使用,我整理一下供初学者参考
- 【良心推荐两款软件】eDiary记笔记软件+截图识别文字软件
- 短语get off to
- 前端基础 - 案例二:酱品购电商网站首页(精简版)