链表的增、删、排序
class Node{
int data;
Node next=null;
public Node(int data) {
this.data = data;
}
}
public class C1 {
//头结点
Node head=null;
public static void main(String[] args) {
C1 linkList = new C1();
linkList.addNode(3);
linkList.addNode(2);
linkList.addNode(1);
linkList.printLink(linkList.head);
System.out.println("len:"+linkList.size(linkList.head));
linkList.delete(2);
linkList.printLink(linkList.head);
System.out.println("len:"+linkList.size(linkList.head));
Node head = linkList.orderList();
linkList.printLink(head);
}
/**
* 插入节点
*/
private void addNode(int data) {
Node node = new Node(data);
if (head==null){
head=node;
return;
}
Node p=head;
while (p.next!=null){
p=p.next;
}
p.next=node;
}
/**
* 给定头结点计算链表长度
* @param head
* @return
*/
private int size(Node head){
int size=0;
Node p=head;
while (p!=null){
size++;
p=p.next;
}
return size;
}
/**
* 打印链表
* @param head
*/
private void printLink(Node head){
Node p=head;
while (p!=null){
System.out.println(p.data);
p=p.next;
}
}
/**
* 删除第index个节点
* @param index
* @return
*/
private boolean delete(int index){
if (index<1||index>size(head)){
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;
i++;
}
return true;
}
/**
* 对链表进行排序
*/
private Node orderList(){
Node nextNode=null;
int tmp=0;
Node curNode=head;
while (curNode.next!=null){
nextNode=curNode.next;
while (nextNode!=null){
if (curNode.data>nextNode.data){
tmp=curNode.data;
curNode.data=nextNode.data;
nextNode.data=tmp;
}
nextNode=nextNode.next;
}
curNode=curNode.next;
}
return head;
}
}
如何删除链表中重复的数据
1、使用hashtable,遍历链表,如果hashtable中不存在该节点,就将该节点添加到hashtable中,如果存在则删除该节点;
private void deleteDuplecate(Node head){
Hashtable<Integer, Integer> table = new Hashtable<>();
Node pre=null;
Node tmp=head;
while (tmp!=null){
if (table.containsKey(tmp.data)){
pre.next=tmp.next;
}else {
table.put(tmp.data,1);
pre=tmp;
}
tmp=tmp.next;
}
}
2、使用双重循环,挨个查找链表中是否有该元素的重复值;
private void deleteDuplecate1(Node head){
Node outerP=head;
while (outerP!=null){
Node innerP=outerP;
while (innerP.next!=null){
if (outerP.data==innerP.next.data){
innerP.next=innerP.next.next;
}else {
innerP=innerP.next;
}
}
outerP=outerP.next;
}
}
找出单链表中的倒数第k个元素
- 先从头遍历一遍计算出链表的长度,然后从头遍历删除第n-k个节点,需要遍历两遍 时间复杂度O(n);
- 从头开始检测距离每个节点k的位置是否为空,如果为空说明当前节点是倒数第k个 时间复杂度O(kn);
- 设置两个指针,第二个指针距离第一个指针k,然后两指针往后移动,直到第二个指针为空 时间复杂度O(n-k);
private Node findElem(int k,Node head){
Node preNode=head;
Node afterNode=preNode;
int t=0;
while (t<k-1&&afterNode!=null){
afterNode=afterNode.next;
t++;
}
if(afterNode==null){
System.out.println("k 不合法");
return null;
}
while (afterNode.next!=null){
preNode=preNode.next;
afterNode=afterNode.next;
}
return preNode;
}
链表反转
private Node reverse(Node head){
Node reHead=null;
Node cur=head;
Node pre=null;
while (cur!=null){
Node tmp=cur.next;
cur.next=pre;
if (tmp==null){
reHead=cur;
}
pre=cur;
cur=tmp;
}
return reHead;
}
如何从尾到头输出单链表
private void printListReversely(Node pListHead){
if (pListHead!=null){
printLink(pListHead.next);
System.out.println(pListHead.data);
}
}
寻找链表的中间节点
- 遍历链表计算链表的长度len,然后找到第len/2个节点,需要遍历两次;
- 指定一个慢指针一次走一步,一个快指针一次走两步,当快指针到达链表尾部的时候,如果链表长度时奇数,则慢指针指向中点,如果是偶数慢指针指向的节点和它的下一个节点都是中点。
private boolean IsLoop(Node head){
Node slow=head;
Node fast=head;
if (fast==null){
return false;
}
while (fast!=null&&fast.next!=null){
fast=fast.next.next;
slow=slow.next;
if (fast==slow){
return true;
}
}
return false;
}
如何寻找入口节点:先找到两个指针相遇的地方,快指针指向这个地方,然后再将慢指针指向链表头,再每次两个指针都移动一次,两个指针相遇的地方就是环入口。
如何在不知道头指针的情况下删除指定结点
如果删除的结点是尾节点,则无法删除;如果删除不是尾节点,则先将它与它的下一个节点值交换,然后删除它的下一个节点;
private boolean deleteNode(Node node){
if (node==null||node.next==null){
return false;
}
int tmp=node.data;
node.data=node.next.data;
node.next.data=tmp;
node.next=node.next.next;
return true;
}
如何判断两个链表是否相交
如何两个链表相交,则它们肯定是同一个尾节点,遍历两个链表,判断它们的尾结点是否相同;
private boolean isIntersect(Node n1,Node n2){
if (n1==null|n2==null){
return false;
}
Node h1=n1;
while (h1.next!=null)
h1=h1.next;
Node h2=n2;
while (h2.next!=null)
h2=h2.next;
return h1==h2;
}
如何找到相交的节点:先判断两个两个链表是否有有交点,顺便计算每个链表的长度,如果len1-len2大于0,则先将指针指向第一个链表的len1-len2处,这时两个指针距离交点的距离相等,然后再移动两个指针,直到指向同一个节点。
private Node isIntersect(Node n1,Node n2){
if (n1==null|n2==null){
return null;
}
Node h1=n1;
int len1=1;
while (h1.next!=null) {
h1 = h1.next;
len1++;
}
Node h2=n2;
int len2=1;
while (h2.next!=null) {
h2 = h2.next;
len2++;
}
if (h1!=h2){
return null;
}
Node t1=n1;
Node t2=n2;
if (len1>len2){
int d=len1-len1;
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;
}