做了一个单链表,可以实现增删改查逆序打印反转合并等操作,但遗留了三个问题:
1、如何将两个未按序号排序的链表按顺序合并?
2、如何将未知数量的链表按顺序合并?
3、下面这个程序为什么会出问题?
假设我创建一个节点A
·在链表1里调用add()方法将A连接到链表1中。
·在链表2里再次调用add()方法添加A节点,却将A节点及后面的节点全部添加到链表2中,这是我们不希望看到的,可是原因是什么呢?
问题见主方法最后一部分注释处,为使程序正常运行我使用addByOrder()方法添加了book1节点,使用add()方法添加会导致程序无限循环。
import java.util.Stack;
//为什么第五十八行调用add方法会出错?如何纠正?list1将book1节点曾经连上过会影响list2连接book1节点?
public class SingleLinkedListDemo {
public static void main(String[] args) {
//测试增删改等基本操作
Book book1=new Book(1,"Joker");
Book book2=new Book(2,"No face man");
Book book3=new Book(3,"Traveler");
Book book4=new Book(4,"Immortal");
Book book5=new Book(5,"Red sacrifices");
Book book6=new Book(6,"Light trap");
Book book7=new Book(7,"Handed man");
SingleLinkedList list1=new SingleLinkedList();
list1.add(book1);
list1.add(book3);
list1.add(book5);
list1.add(book7);
list1.list();
System.out.println();
list1.addByOrder(book2);
list1.addByOrder(book4);
list1.list();
System.out.println();
Book newBook1=new Book(1,"Clown");
list1.update(newBook1);
list1.list();
System.out.println();
list1.del(1);
list1.list();
System.out.println("基本操作结束");
//获取第一个链表的长度
System.out.println("第一个链表的长度为:"+getLength(list1.getHead()));
//逆序打印
System.out.println("逆序打印的链表为:");
reversePrint(list1.getHead());
//反转
System.out.println("反转的链表为:");
reverseList(list1.getHead());
list1.list();
reverseList(list1.getHead());
System.out.println();
list1.list();
System.out.println();
SingleLinkedList list2=new SingleLinkedList();
list2.addByOrder(book1);//为什么这儿调用add方法而不是addByOrder会出错?
list2.add(book6);
list2.list();
System.out.println();
Book book=mergeTwoList(list1.getHead(),list2.getHead());
book=book.next.next;
while(book!=null) {
System.out.println(book);
book=book.next;
}
}
//获取链表的长度
public static int getLength(Book head) {
if(head.next==null) {
return 0;
}
int length=0;
Book temp=head.next;
while(temp!=null) {
length++;
temp=temp.next;
}
return length;
}
//查找链表的倒数第k个节点
public static Book findLastIndexNode(Book head,int index) {
if(head.next==null) {
System.out.println("没有找到");
return null;
}
int size=getLength(head);
if(index<=0||index>size) {
return null;
}
Book temp=head.next;
for(int i=0;i<size-index;i++) {
temp=temp.next;
}
return temp;
}
//逆序打印
public static void reversePrint(Book head) {
if(head.next==null) {
System.out.println("空链表,不能打印");
}
Stack<Book> st=new Stack<Book>();
Book temp=head.next;
while(temp!=null) {
st.push(temp);
temp=temp.next;
}
while(st.size()>0) {
System.out.println(st.pop());
}
}
//反转单链表
public static void reverseList(Book head) {
if(head.next==null||head.next.next==null) {
return;
}
Book temp=head.next;
Book next=null;//指向temp的下一个节点
Book reverseHead=new Book(0,"");
while(temp!=null) {
next=temp.next;
temp.next=reverseHead.next;
reverseHead.next=temp;
temp=next;
}
head.next=reverseHead.next;
}
//单链表的合并
public static Book mergeTwoList(Book head1,Book head2) {
if(head1==null||head2==null) {
return head1!=null?head1:head2;
}
Book head=head1.no<=head2.no?head1:head2;
Book cur1=head==head1?head1:head2;
Book cur2=head==head1?head2:head1;
Book pre=null;//初始为cur1的前一个,之后为cur1和cur2中较小的那一个
Book next=null;//初始为cur2的后一个,之后为上次较大的那一个后面的一个
while(cur1!=null&&cur2!=null) {
if(cur1.no<=cur2.no) {
pre=cur1;
cur1=cur1.next;
}else {
next=cur2.next;
pre.next=cur2;
cur2.next=cur1;
pre=cur2;
cur2=next;
}
}
pre.next=cur1==null?cur2:cur1;
return head;
}
}
//定义一个SingleLinkedList管理书
class SingleLinkedList{
//先初始化一个头节点
private Book head=new Book(0,"");
public Book getHead() {
return head;
}
/*
* 当不考虑编号顺序添加:
* 1、找到当前链表的最后节点
* 2、将这个节点的next指向新的节点
*/
public void add(Book book) {
//因为头节点不能动,我们需要一个辅助结点temp
Book temp=head;
//遍历链表,找到他的最后
while(true) {
if(temp.next==null) {
break;
}
//没有找到,就将temp后移
temp=temp.next;
}
//当退出这个循环时,temp就只想了链表的最后
temp.next=book;
}
// 第二种添加节点的方式:将Book按编号插入指定位置
public void addByOrder(Book book) {
Book temp=head;//temp为添加位置的前一个节点
boolean flag=false;//标志添加的编号是否存在,默认为false
while(true) {
if(temp.next==null) {
break;
}else if(temp.next.no>book.no) {
break;
}else if(temp.next.no==book.no) {
flag=true;
break;
}
temp=temp.next;
}
if(flag) {
System.out.println("编号已存在,不能添加");
}else {
book.next=temp.next;
temp.next=book;
}
}
//根据no修改节点的信息
public void update(Book book) {
if(head.next==null) {
System.out.println("链表为空");
return;
}
Book temp=head.next;
boolean flag=false;
while(true) {
if(temp==null) {
break;
}else if(temp.no==book.no) {
flag=true;
break;
}
temp=temp.next;
}
if(flag) {
temp.name=book.name;
}else {
System.out.printf("没有找到编号为%d的节点",book.no);
}
}
//删除节点
public void del(int no) {
Book temp=head;
boolean flag=false;
while(true) {
if(temp.next==null) {
break;
}else if(temp.next.no==no) {
flag=true;
break;
}
temp=temp.next;
}
if(flag) {
temp.next=temp.next.next;
}else {
System.out.println("要删除的节点不存在");
}
}
//显示链表(遍历)
public void list() {
if(head.next==null) {
System.out.println("链表为空");
return;
}
Book temp=head.next;
while(true) {
if(temp==null) {
break;
}
System.out.println(temp);
temp=temp.next;
}
}
}
//每一本书都是一个节点
class Book {
public int no;
public String name;
public Book next;
//构造器,注意下一个节点Book不用传进来
public Book(int no,String name) {
this.no=no;
this.name=name;
}
//重写一个toString()方法
public String toString() {
return "Book[no="+no+",name="+name+"]";
}
}