数据结构之链表构建及应用

单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。其存储的各节点不一定连续,链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),next指向下一个节点
1.定义单链

package List;
//链节点,有数据域和指针域构成
public class Node {
   public long data; //数据域
   public Node next; //指针域
   
   public Node(long value) {
	   this.data = value;
   }
   public void display() {
	   System.out.print(data+" ");
   }
}

2.链表实现

package List;
//链表,
public class Linklist {
     private Node first;// 首个链接点,相当于车头
     public Linklist() {
    	 first = null; //其链默认指向null
     }
     //在头节点前插入一个节点
     public void insertfirst(long value) {
    	 Node curr = new Node(value);
    	 curr.next = first;  //插入节点指向首节点指向的节点
    	 first = curr;       //首节点更新
     }
     //在头节点后删除一个节点
    public Node removefirst() {
    	Node temp = first;  //定义当前节点
    	first = temp.next;  //直接跳过first.next,从而指向第三个节点
    	return temp;
    }
    //显示链表
    public void display1() {
    	Node curr = first;
    	while(curr != null) //判断当前有元素存在
    	{
    		curr.display();  //调用Node里面的显示方法
    		curr = curr.next;//继续遍历下个节点
    	}
    	System.out.println();
    }
    //查找链节点
    public  Node  find(long value) {
    	Node curr = first;
    	while(curr.data!=value) {
    		if(curr.next==null) {
    			return null;
    		}
    		curr = curr.next;
    	}
    	return curr;		
    }
    //删除节点
    public Node delete(long value) {
    	Node curr = first;
    	Node prev = first;
    	while(curr.data!=value) {
    		if(curr.next==null) {
    			return null;
    		}
    		prev = curr;     //之前的要指向当前的链接点
    		curr = curr.next;//当前的链接点要指向下一个
    		if(curr==first) //判断删除节点是否为首节点
    		{
    			first = first.next;
    			}
    		else {
    				prev.next = curr.next; //删除当前的节点prev(prev.next)》curr(curr.next)》node
    			}
    	}
    	return curr;
    }
}

3.测试代码

package List;
public class TestLinklist {
  public static void main(String[] args) {
	Linklist l1 = new Linklist();
	l1.insertfirst(25);
	l1.insertfirst(36);
	l1.insertfirst(18);
	l1.insertfirst(43);
	l1.display1();
	l1.removefirst();
	l1.display1();
	//查找某个值
	Node t1 = l1.find(36);
	t1.display();
	System.out.println();
	//删除某个值
	Node t2 = l1.delete(36);
	t2.display();
	System.out.println();
	l1.display1();
}
}

4.写在一起便于阅读
这里构建水浒传里面的英雄,参数列表:排名,名字,昵称
通过创建节点类属性来管理节点,创建链表属性来构建链表

package List;
public class singlelinklist {
	public static void main(String[] args) {
		HeroNode hero1 = new HeroNode(1,"宋江","及时雨");
		HeroNode hero2 = new HeroNode(2,"卢俊义","玉麒麟");
		HeroNode hero3 = new HeroNode(3,"吴用","智多星");
		HeroNode hero4 = new HeroNode(4,"林冲","豹子头");
		HeroNode hero5 = new HeroNode(5,"史进","九纹龙");
		//创建单链表
		Singlelist st =new Singlelist();
		st.add(hero1); //添加节点数据
		st.add(hero2);
		st.add(hero3);
		st.add(hero4);
		st.add(hero5);
		st.show(); //显示数据
		
	}
	
}
//创建单链表属性
class Singlelist{
	//初始化一个头节点,好在后部添加数据
	HeroNode head = new HeroNode(0,"","");
	//添加节点方法
	public void add(HeroNode hero) {
		//要找到链尾,向其添加数据,然后将其next指向下一个节点
		HeroNode temp = head; //指向了head
		while(true) {
			//找到链表的最后
			if(temp.next==null) {
				break;//找到了最后节点结束
			}
			temp = temp.next; //指针后移,继续查找
		}//退出循环就指向了最后节点,将该节点指向新节点
		temp.next = hero; //添加进去
	}
	public void show() {
			if(head.next==null) {
				System.out.println("无节点数据");
				return;//找到了最后节点结束
			}
			HeroNode temp = head.next; //指向了head
			while(true) {
				if(temp ==null) {
					break;
				}
				System.out.println(temp); //打印当前节点
				temp = temp.next; //指针后移,继续遍历
		}//退出循环就指向了最后节点,将该节点指向新节点
	}
}
//创建节点属性
class HeroNode {
	public int num;  //编号
	public String name; //名字
	private String pname; //昵称
	public HeroNode next;//指向下一节点
	//构造方法
	public HeroNode(int numb,String nameb,String pnameb ) {
		this.num = numb;
		this.name = nameb;
		this.pname= pnameb;
	}
	//重写toString方法,方便输出信息
	@Override
	public String toString() {
		return "HeroNode [num=" + num + ", name=" + name + ", pname=" + pname + "]";
	}
}

测试结果:
在这里插入图片描述
4.2按排名的方式进行节点插入
重写添加方法与新插入的节点进行序号比较,按排序顺序进行插入,思路如下:
在这里插入图片描述
方法重写如下:

//根据num编号排名进行添加到节点
			public void add2(HeroNode hero) {
				boolean flag = false;//定义排名大小标记,默认新加的节点大
				HeroNode temp = head; //指向了head节点
				while(true){
						if(temp.next==null) {break;}//已经在链表的最后,还要进行序号判断
						//下面进行序号判断
					    if(temp.next.num>hero.num) {
					    	break;//找到插入的位置,在temp与temp.next之间插入
					    	}
					    else if(temp.next.num==hero.num) {
					    	  flag = true;
						      break;
					    }
					       temp =temp.next;//指针后移,进行遍历
					   }
				     if(flag) {  System.out.println("此号码已插入过: num="+hero.num);}
						//下面进行插入操作,插在temp与temp.next之间
				     else { hero.next =temp.next; //新节点指向上一个节点
					        temp.next =hero; //temp的指向由新节点
				       }
		}

根据编号匹配进行信息修改:

					//根据编号进行数据更新,编号是一定的
					public void update(HeroNode newhero) {
					if(head.next==null) {System.out.println("链表为空");
					return;} //判断是否为空,为空不用更新数据
					boolean flag = false; //匹配的标记
					HeroNode temp = head.next;
					while(true) {
					if(temp==null) {  
								break; //已经遍历完 
					 }if(newhero.num ==temp.num) {
						 flag = true;//找到修改的地方
						 break;
						 }
					 temp= temp.next; //继续遍历搜索
					}
					if(flag) {
						newhero.name = temp.name;
						newhero.pname = temp.pname;
					}else {System.out.println("无修改信息");}
				}

删除节点:依据编号相同进行删除
在这里插入图片描述

//删除节点
		public void delete(int num) {
			boolean flag = false; //匹配的标记
			HeroNode temp = head;
			while(true) {
			if(temp.next==null) {  
						break; //已经遍历完 
			 }if(temp.next.num ==num) {
				 flag = true;//找到修改的地方
				 break;
				 }
			 temp= temp.next; //继续遍历搜索
			}
			if(flag) {
				temp.next =temp.next.next;//跳过需要删除的节点
			}else {System.out.println("无修改信息");}
		}

统计节点的有效个数,不包括头结点:传入参数为头节点

		//统计节点的有效个数,不包含头节点
				public  static int getLength(HeroNode head) {
					//判断为不为空
					if( head.next==null) {return 0;}
					int length = 0;//标记个数
					HeroNode temp = head.next; //指向头结点的下一个节点
					while(temp!=null) {
						length++;
						temp = temp.next; //向下进行遍历
					}
					return length;
				}

找出链表倒数第k个节点,思路:先统计链表有效个数,然后匹配倒数第k个
传入参数为头结点和k

		//查找单链表的倒数第K个节点,先统计有效个数,然后查找第K个
		public  static void search(HeroNode head,int k) {
				//判断为不为空
				if( head.next==null) {
					System.out.println("链表无节点");
				    return;}
					int length = 0;//标记有效个数
					int count = 0;//标记查找个数
					HeroNode temp = head.next;
					HeroNode cur = head.next;
					while(temp!=null) {
						length++;
						temp = temp.next; //向下进行遍历
					}//退出循环后找到有效节点数length
					if(k<=length) { //不能超过边界
					while(cur!=null) {
						count++;
						if(count==length+1-k) {
							System.out.println(cur);
							break;
							}//找到倒数第k个
						cur = cur.next; //向下进行遍历
					}
				}else {System.out.println("输入超过了,有效数据为:"+length);}
				
		}
		//统计节点的有效个数,不包含头节点
			public  static int getLength(HeroNode head) {
				//判断为不为空
				if( head.next==null) {return 0;}
				int length = 0;//标记个数
				HeroNode temp = head.next;
				while(temp!=null) {
					length++;
					temp = temp.next; //向下进行遍历
				}
				return length;
				
			}

将单链表进行反转,(百度题)
思路:重新连接一条链,首先创建一个新节 点reverseHead = new HeroNode();
从头开始遍历原来的链表,每遍历一个节点,将其取出,放入新节点的链路
即变为:head.next = reverseHead.next;每次添加后都将后面的节点放在前面了
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200515170418616.png
在这里插入图片描述
在这里插入图片描述
//反转链表,改变原有的结构,如下所示

		//统计节点的有效个数,不包含头节点
			public  static void reverse(HeroNode head) {
				//判断为不为空
				if( head.next==null||head.next.next==null) {return ;}
				HeroNode newNode = new HeroNode(0,"","");//创建新链表的链头
				HeroNode cur = head.next; // 指向head的下一个节点
				HeroNode temp = null;
				while(cur!=null) {
					temp= cur.next ; //保留当前节点的下一节点,便于下次的遍历
					cur.next = newNode.next; //转向新链路,建立头节点与下一节点连接
					newNode.next = cur;   //将它的地址用cur来替代,取出cur
					cur =temp;  //往下进行遍历
				}
				head.next = newNode.next;//将链头节点加入
			}

逆序打印链表
在这里插入图片描述
这里采用栈的方式进行,首先给出栈的应用示例:

		//逆序打印,通过栈来实现
				public static void showresvest(HeroNode head) {
					if(head.next==null) {System.out.println("空链表");}
					Stack<HeroNode> st = new Stack();
					HeroNode temp = head.next;
					while(temp!=null) {
						st.push(temp); //进栈,add也可以
						temp = temp.next;
					}
					//出栈
					while(st.size()>0) {
						System.out.println(st.pop());
					}
				}

所有整合的代码

			package List;
			
			import java.util.Stack;
			
			public class singlelinklist {
				public static void main(String[] args) {
					/*
					 * HeroNode hero1 = new HeroNode(1,"宋江","及时雨"); HeroNode hero2 = new
					 * HeroNode(2,"卢俊义","玉麒麟"); HeroNode hero3 = new HeroNode(3,"吴用","智多星");
					 * HeroNode hero4 = new HeroNode(4,"林冲","豹子头"); HeroNode hero5 = new
					 * HeroNode(5,"史进","九纹龙"); //创建单链表 Singlelist st =new Singlelist();
					 * st.add(hero1); //添加节点数据 st.add(hero2); st.add(hero3); st.add(hero4);
					 * st.add(hero5); st.show(); //显示数据
					 */
					HeroNode hero1 = new HeroNode(1,"宋江","及时雨");
					HeroNode hero2 = new HeroNode(2,"卢俊义","玉麒麟");
					HeroNode hero3 = new HeroNode(3,"吴用","智多星");
					HeroNode hero4 = new HeroNode(4,"林冲","豹子头");
					HeroNode hero5 = new HeroNode(5,"史进","九纹龙");
					//创建单链表
					Singlelist st =new Singlelist();
					st.add2(hero4); //添加节点数据
					st.add2(hero1);
					st.add2(hero3);
					st.add2(hero5);
					st.add2(hero2);
					st.add2(hero5);
					st.show(); //显示数据
					//显示有效个数,将头结点传进去
					System.out.println(getLength(st.getHead()));
					//查找倒数第k个节点
					search(st.getHead(),2);
					//反转链表结构
					System.out.println("反转链表");
					reverse(st.getHead());
					st.show(); //显示数据
					//逆序输出
					showresvest(st.getHead());
				}
				//查找单链表的倒数第K个节点,先统计有效个数,然后查找第K个
					public  static void search(HeroNode head,int k) {
						//判断为不为空
						if( head.next==null) {
							System.out.println("链表无节点");
						    return;}
							int length = 0;//标记有效个数
							int count = 0;//标记查找个数
							HeroNode temp = head.next;
							HeroNode cur = head.next;
							while(temp!=null) {
								length++;
								temp = temp.next; //向下进行遍历
							}//退出循环后找到有效节点数length
							if(k<=length) { //不能超过边界
							while(cur!=null) {
								count++;
								if(count==length+1-k) {
									System.out.println(cur);
									break;
									}//找到倒数第k个
								cur = cur.next; //向下进行遍历
							}
						}else {System.out.println("输入超过了,有效数据为:"+length);}
						
				}
				//统计节点的有效个数,不包含头节点
					public  static int getLength(HeroNode head) {
						//判断为不为空
						if( head.next==null) {return 0;}
						int length = 0;//标记个数
						HeroNode temp = head.next;
						while(temp!=null) {
							length++;
							temp = temp.next; //向下进行遍历
						}
						return length;
						
					}
				
					//反转链表,改变结构如下所示
					//统计节点的有效个数,不包含头节点
					public  static void reverse(HeroNode head) {
						//判断为不为空
						if( head.next==null||head.next.next==null) {return ;}
						//创建新链表的链头
						HeroNode newNode = new HeroNode(0,"","");
						HeroNode cur = head.next; // 指向head的下一个节点
						HeroNode temp = null;
						while(cur!=null) {
							temp= cur.next ; //保留当前节点的下一节点,便于下次的遍历
							cur.next = newNode.next; //转向新链路,建立头节点与下一节点连接
							newNode.next = cur;   //将它的地址用cur来替代,取出cur
							cur =temp;  //往下进行遍历
						}
						head.next = newNode.next;//将链头节点加入
					}
					//逆序打印,通过栈来实现
					public static void showresvest(HeroNode head) {
						if(head.next==null) {System.out.println("空链表");}
						Stack<HeroNode> st = new Stack();
						HeroNode temp = head.next;
						while(temp!=null) {
							st.add(temp); //进栈
							temp = temp.next;
						}
						//出栈
						while(st.size()>0) {
							System.out.println(st.pop());
						}
					}
				
			}
			//创建单链表属性
			class Singlelist{
				//初始化一个头节点,好在后部添加数据
				HeroNode head = new HeroNode(0,"","");
				
				//返回头结点
				public HeroNode getHead() {
					return head;
				}
			
				//单节点进行,添加节点方法
				public void add(HeroNode hero) {
					//要找到链尾,向其添加数据,然后将其next指向下一个节点
					HeroNode temp = head; //指向了head
					while(true) {
						//找到链表的最后
						if(temp.next==null) {
							break;//找到了最后节点结束
						}
						temp = temp.next; //指针后移,继续查找
					}//退出循环就指向了最后节点,将该节点指向新节点
					temp.next = hero; //添加进去
				}
				
					
					
				//根据num编号排名进行添加到节点
				public void add2(HeroNode hero) {
					boolean flag = false;//定义排名大小标记,默认新加的节点大
					HeroNode temp = head; //指向了head
					while(true){
							if(temp.next==null) {break;}//已经在表的最后
						    if(temp.next.num>hero.num) {
						    	break;//找到插入的位置,在temp与temp.next之间插入
						    	}
						    else if(temp.next.num==hero.num) {
						    	  flag = true;
							      break;
						    }
						       temp =temp.next;//指针后移,进行遍历
						   }
					     if(flag) {  System.out.println("此号码已插入过: num="+hero.num);}
							//下面进行插入操作,插在temp与temp.next之间
					     else { hero.next =temp.next; //新节点指向上一个节点
						        temp.next =hero; //temp的指向由新节点
					       }
			}
			   //根据编号进行数据更新,编号是一定的
				public void update(HeroNode newhero) {
					if(head.next==null) {System.out.println("链表为空");
					return;} //判断是否为空,为空不用更新数据
					boolean flag = false; //匹配的标记
					HeroNode temp = head.next;  //表示下一位数据
					while(true) {
					if(temp==null) {  
								break; //已经遍历完 
					 }if(newhero.num ==temp.num) {
						 flag = true;//找到修改的地方
						 break;
						 }
					 temp= temp.next; //继续遍历搜索
					}
					if(flag) {
						newhero.name = temp.name;
						newhero.pname = temp.pname;
					}else {System.out.println("无修改信息");}
				}
				//删除节点
					public void delete(int num) {
						boolean flag = false; //匹配的标记
						HeroNode temp = head;
						while(true) {
						if(temp.next==null) {  
									break; //已经遍历完 
						 }if(temp.next.num ==num) {
							 flag = true;//找到修改的地方
							 break;
							 }
						 temp= temp.next; //继续遍历搜索
						}
						if(flag) {
							temp.next =temp.next.next;//跳过需要删除的节点
						}else {System.out.println("无修改信息");}
					}
				public void show() {
						if(head.next==null) {
							System.out.println("无节点数据");
							return;//找到了最后节点结束
						}
						HeroNode temp = head.next; //指向了head
						while(true) {
							if(temp ==null) {
								break;
							}
							System.out.println(temp); //打印当前节点
							temp = temp.next; //指针后移,继续遍历
					}//退出循环就指向了最后节点,将该节点指向新节点
				}
			}
			//创建节点属性
			class HeroNode {
				public int num;  //编号
				public String name; //名字
				public String pname; //昵称
				public HeroNode next;//指向下一节点
				//构造方法
				public HeroNode(int numb,String nameb,String pnameb ) {
					this.num = numb;
					this.name = nameb;
					this.pname= pnameb;
				}
				//重写toString方法,方便输出信息
				@Override
				public String toString() {
					return "HeroNode [num=" + num + ", name=" + name + ", pname=" + pname + "]";
				}
			}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值