package JBLinkList;
public class MyLinkList {
Node head ;
public MyLinkList(){
head = null;
}
/**
* 添加结点(尾部)
* @param d
*/
public void addNode(int d){
Node newNode = new Node(d);
if(head == null){
head = newNode;
return;
}
Node tmp = head;
while(tmp.next!= null){
tmp = tmp.next;
}
tmp.next = newNode;
}
/**
* 删除结点
* 1、判断位置是否合理
* 2、删除头结点i=1 head =head.next
* 3、其他结点 i=2....
* 判断是否为空
* 不为空
* 是否是要删除的结点,删除 preNode.next = curNode.next
* 不是则向右移 preNode = curNode ; curNode = curNode.next
* 为空返回true
* @param index
* @return
*/
public boolean deleteNode(int index){
if (index<1 || index>length()) {
return false;
}
if (index==1) {
head = head.next;
return true;
}
int i = 2;
Node preNode = head;
Node curNode = preNode.next;
while(curNode!=null){
if (i==index) {
preNode.next = curNode.next;
return true;
}
preNode = curNode ;
curNode = curNode.next;
}
return true;
}
/**
* 查找结点
*/
public Node finNode(int i){
Node node = head;
while(node.data != i){
if(node.next!=null){
node = node.next;
}
return null;
}
return node;
}
/**
* 返回长度
* tmp = tmp.next
* length++
* @return
*/
public int length() {
int length = 0;
Node tmp = head;
while(tmp!=null){
length++;
tmp = tmp.next;
}
return length;
}
/**
* 排序
* 选择排序
* @return
*/
public Node orderList(){
Node nextNode = null;
int temp = 0;
Node curNode = head;
//curNode作为头结点循环的次数
while(curNode.next!=null){
nextNode = curNode.next;
//除头结点以外其他结点循环比较找到最小的结点与当前头结点数据交换
while(nextNode.next!=null){
if (curNode.data>nextNode.data) {
temp = curNode.data;
curNode.data = nextNode.data;
nextNode.data = temp;
}
//右移遍历结点
nextNode = nextNode.next;
}
//循环起始点右移
curNode=curNode.next;
}
return head;
}
/**
* 打印结点
* 从头结点开始
* 向右移动tmp = tmp.next
*/
public void printList(){
Node tmp = head;
while(tmp !=null){
System.out.println(tmp.data);
tmp = tmp.next;
}
}
/**
* 删除重复元素
* @param head
*/
public void deleteDuplecate(Node head){
Node p = head;
while (p!=null) {
Node q = p;
while (q.next!=null) {
if(p.data == q.next.data){
q.next = q.next.next;
}
q = q.next;
}
p = p.next;
}
}
/**
* 找到链表中倒数第K个元素
* 1、设置两个指针,其中一个指针比另一个先走K-1步
* 2、若先行指针的下一元素不为空,两个指针同时往前移动
* 3、循环直到先行指针的下一元素为空,返回后行指针的位置。
* @param head
* @param k
* @return
*/
public Node findElem(Node head, int k){
if(k<1){
return null;
}
Node p1 = head;
Node p2 = head;
for (int i = 0; i <k-1 && p1!=null; i++) {
p1 = p1.next;
if (p1==null) {
System.out.println("K不合法");
return null;
}
}
while (p1.next!=null) {
p1 = p1.next;
p2 = p2.next;
}
return p2;
}
/**
* 实现链表的反转
* @param args
*/
public Node ReverseList1(Node head) {
if(head==null)
return null;
Node newHead = null;
Node pNode = head;
Node pPrev = null;
while(pNode!=null){
Node pNext = pNode.next;
if(pNext==null)
newHead = pNode;
pNode.next = pPrev;
pPrev = pNode;
pNode = pNext;
}
return newHead;
}
/* public ListNode ReverseList(ListNode head){
ListNode pReversedHead = null;
ListNode pNode = head;
ListNode pPre = null;
while (pNode != null) {
ListNode pNext = pNode.next;
if(pNode.next==null){//当前结点已经是最后一个节点
pReversedHead = pNode;//需要把最后这个节点的值保存下来,因为前面的链断了就无法查找到最后这个结点
}
pNode.next=pPre ;//不是最后一个结点就把这个结点指向后一个结点的链断开指向前一个结点
pPre = pNode;//向后移循环
pNode = pNext;//向后移循环
}
return pReversedHead;//已经到最后一个结点,将保存的最后一个结点设为该链表的头结点
}*/
public void ReverseIteratively(Node head){
Node pReversedHead = head;
Node pNode = head;
Node pPre = null;
while (pNode != null) {
Node pNext = pNode.next;
if(pNode.next==null){//当前结点已经是最后一个节点
pReversedHead = pNode;//需要把最后这个节点的值保存下来,因为前面的链断了就无法查找到最后这个结点
}
pNode.next=pPre ;//不是最后一个结点就把这个结点指向后一个结点的链断开指向前一个结点
pPre = pNode;//向后移循环
pNode = pNext;//向后移循环
}
this.head = pReversedHead;//已经到最后一个结点,将保存的最后一个结点设为该链表的头结点
}
/**
* 从尾到头打印出链表
*/
public void printListReversely(Node pListHead){
if (pListHead!=null) {
printListReversely(pListHead.next);//递归打印后面的结点
System.out.print(pListHead.data);//再输出结点本身
}
}
/**
* 查找中间元素
* 1、两个指针同时从头结点遍历
* 2、一个快指针一次走两步,一个慢指针一次走一步
* 3、当快指针走到尾部时,慢指针恰好到达链表中部
* @param head
* @return
*/
public Node SearchMid(Node head){
Node p = this.head;
Node q = this.head;
while(p!=null&&p.next!=null&&p.next.next!=null){
p = p.next.next;
q=q.next;
}
return q;
}
/**
* 检测一个链表是否有环和环的入口
* 1、声明两个指针,fast slow
* 2、fast一次走两步,慢指针一次走一步,当快指针等于慢指针是证明有环
* 3、找到入口方法
* 3.1 r代表环长,L代表链长,x代表环入口到相遇点的距离,a代表起点到环入口距离
* slow走了s,fast走了2s,
* 2s=s+nr,
* s=a+x=nr=(n-1)r+r,
* L=r+a,r=L-a
* a+x=(n-1)r+L-a
* a=(n-1)r+(L-a-x)
* (L-a-x)代表相遇点到环入口的距离。
* 一指针从起始点开始
* 另一指针从相遇点开始
* 每次各走一步两个指针必定相遇,相遇点则是环入口
*/
public Node FindLoopPort(Node head){
Node fast = head;
Node slow = head;
if(fast==null && fast.next==null){
return null;
}
while (fast!=null&&fast.next!=null) {
fast = fast.next.next;
slow = slow.next;
if (slow.data == fast.data) {
fast = head;
while(slow.data != fast.data){
slow = slow.next;
fast = fast.next;
}
return slow;
}
}
return null;
}
/**
* 不知道头结点的情况下删除指针
* 1、如果删除结点是尾结点,无法删除,因为无法使其前驱的next为空
* 2、如果删除结点不是尾结点,则交换该结点与其后继结点的值,然后删除后继结点
*/
public boolean deleteNode(Node n){
if (n==null||n.next==null) {
return false;
}
int tmp = n.data;
n.data = n.next.data;
n.next.data = tmp;
n.next = n.next.next;
return true;
}
/**
* 判断两个链表是否相交,找到相交点
* 1、判断是否相交
* 1.1 循环找到两个链表的尾结点,并记录各自长度len1 、len2
* 1.2 尾结点相同说明相交
* 2、找相交点
* 2.1 先遍历到较长的链表第len2-len1位置的结点P(假设2较长)
* 2.2 然后再同时遍历两个链表,直到遇到相同结点,此结点便是相交点
*/
public Node getFirstMeetNode(Node h1, Node h2){
if(h1==null || h2==null){
return null;
}
Node tail1 = h1;
int len1 = 1;
while(tail1.next!=null){
tail1 = tail1.next;
len1++;
}
Node tail2=h2;
int len2 = 2;
while(tail2!=null){
tail2 = tail2.next;
len2++;
}
if(tail1!=tail2){
return null;
}
Node t1 = h1;
Node t2 = h2;
if(len1>len2){
int d = len1-len2;
while(d!=0){
t1 = t1.next;
d--;
}
}
else{
int d = len2-len1;
while(d!=0){
t2 = t2.next;
d--;
}
}
while(t1 != t2){
t1 = t1.next;
t2 = t2.next;
}
return t1;
}
}