给定单链表:1 -> 2 -> 3 -> 4 -> 5 -> null
将中间元素修改为双向链表节点
这里的中间元素是3
3 -> next
应该指向4
3 -> prev
应该指向1
谁能建议怎么做?面试官给了我提示use interface
,但我无法弄清楚怎么做。
我必须遍历这个链表并打印所有节点,当它到达中间时,打印下一个和上一个指向的位置,然后打印到列表的末尾。
Expected output
: 1, 2, Middle: 3, Prev: 1, Next: 4, 5
我在添加中间节点时遇到问题。
所以,这">有效",但如果期望在面试中回答这个问题,那就太费力了。
链接列表
public class LinkedList {
public interface Linkable<V, L extends Linkable> {
V getValue();
L getNext();
void setNext(L link);
}
public static class Node implements Linkable<Integer, Linkable> {
int value;
Linkable next;
Node(int value) {
this.value = value;
}
@Override
public Integer getValue() {
return value;
}
@Override
public Linkable getNext() {
return next;
}
@Override
public void setNext(Linkable link) {
this.next = link;
}
}
private Linkable head;
public boolean isEmpty() {
return this.head == null;
}
public Linkable getHead() {
return head;
}
public void add(int v) {
Node next = new Node(v);
if (isEmpty()) {
this.head = next;
} else {
Linkable tmp = this.head;
while (tmp.getNext() != null) {
tmp = tmp.getNext();
}
tmp.setNext(next);
}
}
}
接口
interface DoublyLinkable<V, L extends LinkedList.Linkable> extends LinkedList.Linkable<V,L> {
LinkedList.Linkable getPrev();
void setPrev(LinkedList.Linkable prev);
}
双节点
public class DoubleNode extends LinkedList.Node implements DoublyLinkable<Integer, LinkedList.Linkable> {
LinkedList.Linkable prev;
public DoubleNode(int value) {
super(value);
}
@Override
public LinkedList.Linkable getPrev() {
return prev;
}
@Override
public void setPrev(LinkedList.Linkable prev) {
this.prev = prev;
}
}
司机
输出
1, 2, Middle: 3, Prev: 1, Next: 4, 5
public class Driver {
public static LinkedList getList() {
LinkedList list = new LinkedList();
for (int i = 1; i <= 5; i++) {
list.add(i);
}
return list;
}
public static void main(String[] args) {
LinkedList list = getList();
LinkedList.Linkable head = list.getHead();
LinkedList.Linkable beforeMiddle = null;
LinkedList.Linkable middle = list.getHead();
LinkedList.Linkable end = list.getHead();
if (head != null) {
// find the middle of the list
while (true) {
if (end.getNext() == null || end.getNext().getNext() == null) break;
beforeMiddle = middle;
middle = middle.getNext();
end = end.getNext().getNext();
}
// Replace middle by reassigning the pointer to it
if (beforeMiddle != null) {
DoubleNode n = new DoubleNode((int) middle.getValue()); // same value
n.setPrev(list.getHead()); // point back to the front
n.setNext(middle.getNext()); // point forward to original value
beforeMiddle.setNext((DoublyLinkable) n);
middle = beforeMiddle.getNext();
}
// Build the "expected" output
StringBuilder sb = new StringBuilder();
final String DELIMITER = ", ";
head = list.getHead();
boolean atMiddle = false;
if (head != null) {
do {
if (head instanceof DoublyLinkable) {
atMiddle = true;
String out = String.format("Middle: %d, Prev: %d, ", (int) head.getValue(), (int) ((DoublyLinkable) head).getPrev().getValue());
sb.append(out);
} else {
if (atMiddle) {
sb.append("Next: ");
atMiddle = false;
}
sb.append(head.getValue()).append(DELIMITER);
}
head = head.getNext();
} while (head != null);
}
sb.setLength(sb.length() - DELIMITER.length());
System.out.println(sb.toString());
}
}
}
根据定义,单链表仅由单链接节点组成,双链列表仅由双链接节点组成。否则。都不是。
根据定义,双链表的字段prev
必须指向前一个元素。
无论你应该建造什么。这是没有明确规定的东西。因此,如果你真的在面试中被问到这个问题(并且没有误解这个问题 - 也许他想让你指出 ghis 违反了界面?(这是 http://thedailywtf.com/的代码恐怖故事的一个案例 - "不称职的面试官"部分。
如果你还没有,你最好定义一个 length(( 函数,这样给定一个链表,你可以知道它有多少个节点。
由于Cereal_Killer对这个答案的先前版本的回应,我注意到该列表首先是一个单链表,您只需要使中间节点同时链接到下一个节点和某个前一个节点。
现在我猜你已经定义了两个结构(结构体、类或任何取决于你使用的语言(。因此,假设您Node_s
定义为仅具有next
指针的节点,以及同时具有next
和prev
指针的Node_d
节点。(Node_d
可能继承自Node_s
,因此您只需在子类中添加 prev
属性(。知道了这一点,上面的代码应该做你需要的:
function do_it(my_LinkedList linkedList({
int i_middle;
int length = linkedList.length();
if ( (length ÷ 2 ) != 0 ) i_middle = length / 2;
else return -1;
Node_s aux = linkedList.first();
int index = 0;
Node_d middle= null;
while (aux != null) {
if (index == i_middle - 1){ //now aux is the middle's previous node
middle.data = aux.next.data; //aux.next is the middle singly node, we assignate the data to the new double linked node
middle.prev = aux; //as we said, aux is the prev to the middle
midle.next = aux.next.next; //so aux.next.next is the next to the middle
print(what you need to print);
}else {
print("Node " + index " next: "+ aux.next);
}//end if
index++;
aux = aux.next;
} //end while
}//end function
前面的代码应该执行您需要的操作。我用某种伪 java 代码编写了答案,所以如果你不熟悉 Java 或不了解我的伪代码的作用,请告诉我。无论如何,我的代码的想法可能会带来一些麻烦,具体取决于您使用的语言,因此您必须对其进行调整。
请注意,在程序执行结束时,您的数据结构不会是单链表,也不会是双链表,因为您将有linkedList.length() - 1
节点以符号方式链接,但中间的节点将有两个链接。
希望这有帮助。