链表
链表是由节点构成的,这个节点我们可以通过建立一个类来实现它。这个类我们通常选用内部类。
class TestLink{
class Entry{
int data;
Entry next;
public Entry() {
next = null;
}
public Entry(int data) {
this.data = data;
next = null;
}
}
}
链表分为有头结点的链表和无头节点的链表,头结点不储存数据。本篇博客用的是头结点的链表。
注意链表要创建一个构造方法初始化头节点,否则会产生空指针异常
Entry head;//成员变量
public TestLink() {//构造函数
head = new Entry();
}
1.头插
public void insertHead(int val) {
Entry cur = new Entry(val);//插入的点
cur.next = head.next;//把插入的点next指向head的下一个节点
head.next=cur;//head的next指向插入的点
}
2.尾插
遍历链表的时候要注意while(cur.next!=null)和while(cur!=null)的区别。
前者遍历完cur是链表尾元素,后者遍历完cur是null.
public void insertTail(int val) {
Entry goal = new Entry(val);//要插入的点
Entry cur = head;//用来遍历链表
while(cur.next!=null) {//当cur.next为null即cur已经在链表尾部,退出循环
cur = cur.next;
}
cur.next=goal;//尾插
}
3.获得链表长度
public int getLength() {
Entry cur = head;//用来遍历链表
int count = 0;//计数器
while(cur.next != null) {
cur =cur.next;
count++;
}
return count;
}
4.任意位置插入
public void insert(int val,int post) {
Entry cur = head;//用来遍历链表
if(post >= 0 && post <= this.getLength()) {//找到插入的位置前的的那一个节点
for(int i=0;i<post;i++) {
cur = cur.next;
}
}
Entry entry = new Entry(val);
entry.next=cur.next;//插入
cur.next=entry;
}
5.返回下标
public int valueOf(int val) {
Entry cur = head.next;
int count = 0;
while(cur != null) {
if(cur.val == val) {
count++;
return count;
}
count++;
cur = cur.next;
}
return -1;
}
6.删除指定元素
public void remove(int val) {
int j = valueOf(val);
if(j < 1) {
return;
}
Entry cur = head.next;
Entry pr = head;
for (int i = 1; i < j; i++) {
cur = cur.next;
pr =pr.next;
}
pr.next = cur.next;
}
7.链表的逆置
public Entry reverse(){
Entry pre = null;//
Entry newHead = null;//用来存放逆置后链表的头结点
Entry cur = head;//用来遍历链表
while(cur != null) {//当cur.next==null时即cur到尾部时再循环一次把cur变成头指针。
Entry curNext = cur.next;
if(curNext == null){
newHead = cur;
}
cur.next = pre;
pre = cur;
cur = curNext;
}
return newHead;
}
8.求倒数第k个元素
public Entry getPost(int k) {
if(head == null) {
return -1;
}
Entry cur = head;//用来遍历链表
if(k < 0 || k > this.getLength()) {//如果插入的位置小于零或大于链表长度返回null
return null;
}
for(int i=0;i<this.getLength()-k+1;i++) {//找到倒数第k个位置
cur =cur.next;
}
return cur;
}
9.求两个链表是否相交
public boolean isCut(TestLink t1,TestLink t2) {
TestLink.Entry head1 = t1.head;
TestLink.Entry head2 = t2.head;
int len1 = t1.getLength();
int len2 = t2.getLength();
int myLen = len1-len2;//两条链表的长度差
if(myLen < 0) {//head1指向长链表表头
head1 = t2.head;
head2 = t1.head;
}
for(int i=0;i< myLen;i++) {//head1到在长链表上移动至和端链表对齐
head1 = head1.next;
}
while(head1 != null && head2 !=null && head1 != head2) {//两个遍历节点同时向后移,如果到尾部结束循环或两个节点相交结束循环
head1 = head1.next;
head2 = head2.next;
}
if(head1 == head2) {//相交返回true
return true;
}
return false;
}
10.判断链表是否有环,并且求入口点和环长
public boolean judgeLoop() {
Entry fast = head;//快节点
Entry slow = head;//慢节点
while(fast.next != null && fast.next.next != null) {//当快节点到尾部的时候循环结束,因为快节点每次要后移两格所以要加上fast.next.next不等于空的条件,否则会产生空指针异常
fast = fast.next.next;
slow = slow.next;
if(fast == slow) {//相交返回true
return true;
}
}
return false;
}
入口点
public int intoLoop(){
Entry fast = head;
Entry slow = head;
while(fast.next != null && fast.next.next != null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow) {
break;
}
}
slow = head;
while(fast != slow){
fast = fast.next;
slow = slow.next;
}
return slow.data;
}
环长
当快慢节点第二次相遇时,慢节点从第一次到第二次相遇走的距离即环长。
public int getLoopLength() {
Entry fast = head;
Entry slow = head;
boolean tag = false;
int length = 0;
while(fast.next != null && fast.next.next != null) {
fast = fast.next.next;
slow = slow.next;
if(fast == slow && tag == true) {
break;
}
if(fast == slow && tag == false) {
tag =true;
}
if(tag == true ) {
length++;
}
}
return length;
}
11.合并两个链表
将两个递增链表合并成一个递增链表
public static Entry mergeLink(Link l1,Link l2) {
Link.Entry p1 = l1.head.next;
Link.Entry p2 = l2.head.next;
Link.Entry newHead = null;
if(p1.data<p2.data) {//确认头结点(值小的为头结点)
newHead = l1.head;
}else {
newHead = l2.head;
}
Link.Entry tmpHead = newHead;//tmpHead相当于一个缝衣服的针将两个链表串起来
while(p1 != null && p2 != null){
if(p1.data < p2.data){
tmpHead.next = p1;
p1 = p1.next;
}else{
tmpHead.next = p2;
p2 = p2.next;
}
tmpHead = tmpHead.next;
}
if(p1 != null){//如果p1链表没结束,就把p1后面的串上去
tmpHead.next = p1;
}
if(p2 != null){//如果p2链表没结束,就把p2后面的串上去
tmpHead.next = p2;
}
return newHead;
}