链表的应用--java
问题一
- 如何使用一个高效的存储结构来改进双向链表
- 答:使用LinkedList,即异或链表,此数据结构的ADT如下
public class LinkdedNode{
int data;
LinkedNode pridiff;
}
本结构的神奇之处在于它改进了双向列表,不需要再额外的有一个空间,用来单独存储前置节点和后置节点的位置
-
具体证明过程如下
对于任意的链表
-
存在:
A的next = NULL XOR B
B的next = A XOR C
C的next = B XOR D
证明方法如下,
已知:
固存在当我们想要移动 B节点的时候
如果想要向前移动
则有(A XOR C)XOR C = A
如果想要向后移动
则有 (A XOR C)XOR A = C -
疑问:我B要想要向前移动,如何获取C的值呢?
-
答:这里需要做一步异或,因为我们已经移动到了B因此我们一定知道B的前继节点的地址,因此才可以知道下一个C的地址
java代码实现:
暂无,困于两地址的异或操作
问题二:找到链表的倒数第n个节点
package day04;
/**
* @author 海绵宝宝
* @create 2019- 10- 20 17:14
**/
public class list {
public static class ListNode{
private int data;
//设置私有成员变量 Data
private ListNode next;
//设置私有吓一跳的指针
public ListNode(int data){
this.data = data;
}
public void setData(int data){
this.data = data;
}
public int getData(){
return this.data;
}
public void setNext(ListNode next){
this.next = next;
}
public ListNode getNext(){
return this.next;
}
//以上为简单的增删更新
int ListLength(){
int length = 0;
ListNode currentNode = this;
while (currentNode!=null){
currentNode=currentNode.getNext();
length++;
}
return length;
}
ListNode InsertInLinkedList(ListNode headNode,ListNode nodeToInsert,int position){
if (headNode == null){
return nodeToInsert;
}
if (position==1){
headNode.setNext(nodeToInsert);
return headNode;
}
else
{
ListNode previousNode = headNode;
int count =0;
while (count<=position-1){
previousNode=previousNode.getNext();
count++;
}
ListNode currenNode = previousNode.getNext();
nodeToInsert.setNext(currenNode);
previousNode.setNext(nodeToInsert);
}
return headNode;
}
ListNode addlist(int data,ListNode headNode){
ListNode listNode = new ListNode(data);
headNode = headNode.InsertInLinkedList(headNode, listNode, listNode.ListLength());
return headNode;
}
ListNode deletelist(ListNode headNode){
return null;
}//JAVA中会自动实现这一部分
ListNode DeleteNodeFromLinkedList(ListNode headNode,int position){
if (headNode==null)return null;
if (position<1||position>headNode.ListLength()){
System.out.println("error,The location you entered is out limit.");
}
if (position==1){
ListNode currentlist = headNode.getNext();
headNode=null;
return currentlist;
}
else{
ListNode previousnode = headNode;
int count = 1;
while (count<position){
previousnode = previousnode.getNext();
count++;
}
ListNode currentNode = previousnode.getNext();
previousnode.setNext(currentNode.getNext());
currentNode = null;
}
return headNode;
}
public void add(int data){
ListNode currentNode = new ListNode(data);
ListNode node = this;
while (node.getNext()!=null){
node = node.getNext();
}
node.setNext(currentNode);
}
}
public static void PrintList(ListNode headNode){
while (headNode!=null){
System.out.print(headNode.getData()+" ");
headNode= headNode.getNext();
}
System.out.println();
}
public static void main(String[] args) {
ListNode listNode = new ListNode(-1);
// listNode.setData(3);
for (int i = 0; i < 19; i++) {
listNode.add(i);
}
//PrintList(listNode);
}
}
为了方便各位读者学习,因此直接给出相关的已经实现好的数据结构和部分方法供大家学习
方法一:
//method01
//a stupid method不是很想实现它...
public static ListNode Found_n_method_01(ListNode node, int position){
while (node!=null){
ListNode temp = node;
int count = 0;
while (temp!=null){
count++;
temp = temp.getNext();
}
if (count==position){
return node;
}
node = node.getNext();
}
System.out.println("not found");
return null;
}
答题思路就是,我不断去看从我这个节点到最后的长度是不是N,如果是的话,我们就直接return这个值。
此方法的时间复杂度为O(n^2),空间复杂度为O(1)
a stupid method
方法二
//Method02
//a normal method
public static ListNode Found_n_method_02(ListNode node, int position){
if (position>node.ListLength()) {
System.out.println("not found");
return null;
}
int limit = node.ListLength() - position;
for (int i = 0; i < limit; i++) {
node = node.getNext();
}
return node;
}
答题思路就是,我们首先遍历一遍整个列表,得到长度,之后在进行移动
此方法的时间复杂度为O(n),空间复杂度为O(1)
这是一种比较简单的做法,但是·,我们能不呢个再次优化他呢
方法三—双指针
在java中其实并没有指针的概念,这里只是简单的借用一下指针的概念方便大家理解
//Method03
//a great method
public static ListNode Found_n_method_03(ListNode node, int position){
ListNode fTemp = node;
ListNode sTemp = node;
while (position>1){
sTemp = sTemp.getNext();
position--;
}
while (sTemp.getNext()!=null){
sTemp=sTemp.getNext();
fTemp=fTemp.getNext();
}
return fTemp;
}
具体思路就是,我首先使用一个指针指向头部,另一个指针和它相差n-1个位置,这样就可以保证,当最后一个指针的getNext()==null之后,头部指针和相差n-1个位置