Java实现双向链表和循环链表

学数据结构的时候一直用的C语言,用指针用的比较习惯了,Java没有指针,但是写了写试了试发现还是比较容易的。

帮别人写的作业,用Java实现双向链表和循环链表,还得是图形界面程序,真是醉了~

 

public class LinkListData {
	public String value;
	public LinkListData next;
	public LinkListData previous;
	int tag;
	public LinkListData(String value){
		this.value=value;
	}
}
 

核心!链表上的每个节点的实现。感觉比学C的时候用结构体和指针好用多了。 

其中,定义了一个int tag的作用是用于循环链表中确定为头结点,不然循环起来没完了。。

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import com.view.LinkListView;
import javax.swing.JButton;
import javax.swing.JFrame;

public class LinkListStart extends JFrame implements ActionListener {
	JButton jb1,jb2;
	public LinkListStart(){
		jb1=new JButton("双向链表");
		jb1.addActionListener(this);
		jb1.setPreferredSize(new Dimension(100, 40));
		jb2=new JButton("循环链表");
		jb2.addActionListener(this);
		jb2.setPreferredSize(new Dimension(100, 40));
		this.setLayout(new FlowLayout());
		this.setBounds(400, 150, 300, 100);
		this.setVisible(true);
		this.setFocusable(true);
		this.add(jb1);
		this.add(jb2);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	public static void main(String args[]){
		new LinkListStart();
	}

	@Override
	public void actionPerformed(ActionEvent arg0) {
		// TODO Auto-generated method stub
		if(arg0.getSource()==jb1){
			this.dispose();
			new LinkListView(true);
		}
		if(arg0.getSource()==jb2){
			this.dispose();
			new LinkListView(false);
		}
	}

}

初始选择界面,通过实例化LinkListView中的不同参数来使 LinkListView进行增删时选择不同数据处理类。

 

import java.awt.Font;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.SwingConstants;

import com.service.LinkListCircularService;
import com.service.LinkListData;
import com.service.LinkListService;

public class LinkListView extends JFrame implements ActionListener {
	private JLabel jl1,jl2,jl3,jl4,jl5,jl6,jl7,jl8,jl9,jl10;
	private JTextField jt1,jt2,jt3,jt4,jt5,jt6,jt7,jt8;
	private JButton jb1,jb2,jb3,jb4,jb5,jb6,jb7,jb8,jb9,jb10,jb11,jb12;
	private JSeparator sp1,sp2;
	private int length;
	private LinkListService ls;
	private LinkListData data,showdata;
	public LinkListView(){           //无参的构造函数一定要写,不然出现了(The constructor ... is undefined)的错误
	}
 	public LinkListView(boolean x){
		jl1=new JLabel("数据列表");
		jl1.setBounds(50, 20, 70, 40);
		jl1.setFont(new Font("宋体",Font.BOLD, 16));
		this.add(jl1);
		jt1=new JTextField();
		jt1.setBounds(130, 20, 320, 40);
		this.add(jt1);
		
		jl2=new JLabel("增加");
		jl2.setBounds(220, 100, 70, 60);
		jl2.setFont(new Font("宋体",Font.BOLD, 22));
		this.add(jl2);
		jt2=new JTextField();
		jt2.setBounds(300, 110, 70, 40);
		this.add(jt2);
		jl3=new JLabel("位置");
		jl3.setBounds(220, 160, 70, 60);
		jl3.setFont(new Font("宋体",Font.BOLD, 15));
		this.add(jl3);
		jb1=new JButton("开头");
		jb1.setBounds(270, 170, 50, 40);
		jb1.setMargin(new Insets(0, 0, 0, 0));   //设定Button中标签周围的空白
		jb1.setFont(new Font("宋体",Font.BOLD, 15));
		jb1.addActionListener(this);
		this.add(jb1);
		jb2=new JButton("结尾");
		jb2.setBounds(330, 170, 50, 40);
		jb2.setMargin(new Insets(0, 0, 0, 0));
		jb2.setFont(new Font("宋体",Font.BOLD, 15));
		jb2.addActionListener(this);
		this.add(jb2);
		jb3=new JButton("指定");
		jb3.setBounds(390, 170, 50, 40);
		jb3.setMargin(new Insets(0, 0, 0, 0));
		jb3.setFont(new Font("宋体",Font.BOLD, 15));
		jb3.addActionListener(this);
		this.add(jb3);
		jt3=new JTextField();
		jt3.setBounds(440, 170, 35, 40);
		this.add(jt3);
		
		jl4=new JLabel("删除");
		jl4.setBounds(220, 240, 70, 60);
		jl4.setFont(new Font("宋体",Font.BOLD, 22));
		this.add(jl4);
		jl5=new JLabel("位置");
		jl5.setBounds(220, 300, 70, 60);
		jl5.setFont(new Font("宋体",Font.BOLD, 15));
		this.add(jl5);
		jb4=new JButton("开头");
		jb4.setBounds(270, 310, 50, 40);
		jb4.setMargin(new Insets(0, 0, 0, 0));   
		jb4.setFont(new Font("宋体",Font.BOLD, 15));
		jb4.addActionListener(this);
		this.add(jb4);
		jb5=new JButton("结尾");
		jb5.setBounds(330, 310, 50, 40);
		jb5.setMargin(new Insets(0, 0, 0, 0));
		jb5.setFont(new Font("宋体",Font.BOLD, 15));
		jb5.addActionListener(this);
		this.add(jb5);
		jb6=new JButton("指定");
		jb6.setBounds(390, 310, 50, 40);
		jb6.setMargin(new Insets(0, 0, 0, 0));
		jb6.setFont(new Font("宋体",Font.BOLD, 15));
		jb6.addActionListener(this);
		this.add(jb6);
		jt4=new JTextField();
		jt4.setBounds(440, 310, 35, 40);
		this.add(jt4);
		
		jl6=new JLabel("修改");
		jl6.setBounds(220, 380, 70, 60);
		jl6.setFont(new Font("宋体",Font.BOLD, 22));
		this.add(jl6);
		jt5=new JTextField();
		jt5.setBounds(300, 390, 70, 40);
		this.add(jt5);
		jl7=new JLabel("位置");
		jl7.setBounds(220, 440, 70, 60);
		jl7.setFont(new Font("宋体",Font.BOLD, 15));
		this.add(jl7);
		jb7=new JButton("开头");
		jb7.setBounds(270, 450, 50, 40);
		jb7.setMargin(new Insets(0, 0, 0, 0));   
		jb7.setFont(new Font("宋体",Font.BOLD, 15));
		jb7.addActionListener(this);
		this.add(jb7);
		jb8=new JButton("结尾");
		jb8.setBounds(330, 450, 50, 40);
		jb8.setMargin(new Insets(0, 0, 0, 0));
		jb8.setFont(new Font("宋体",Font.BOLD, 15));
		jb8.addActionListener(this);
		this.add(jb8);
		jb9=new JButton("指定");
		jb9.setBounds(390, 450, 50, 40);
		jb9.setMargin(new Insets(0, 0, 0, 0));
		jb9.setFont(new Font("宋体",Font.BOLD, 15));
		jb9.addActionListener(this);
		this.add(jb9);
		jt6=new JTextField();
		jt6.setBounds(440, 450, 35, 40);
		this.add(jt6);
		
		sp1=new JSeparator(SwingConstants.HORIZONTAL);        //水平分隔符
		sp1.setBounds(0, 80, 500, 1);
		this.add(sp1);
		sp2=new JSeparator(SwingConstants.VERTICAL);          //垂直分隔符
		sp2.setBounds(180, 80, 1, 480);
		this.add(sp2);
		
		jl8=new JLabel("查询");
		jl8.setBounds(20, 100, 70, 60);
		jl8.setFont(new Font("宋体",Font.BOLD, 22));
		this.add(jl8);
		jl9=new JLabel("当前数据",JLabel.CENTER);
		jl9.setBounds(55, 140, 70, 60);
		jl9.setFont(new Font("宋体",Font.BOLD, 16));
		this.add(jl9);
		jt7=new JTextField();
		jt7.setBounds(50, 200, 80, 50);
		this.add(jt7);
		jb10=new JButton("上一个");
		jb10.setBounds(20, 270, 50, 40);
		jb10.setMargin(new Insets(0, 0, 0, 0));
		jb10.setFont(new Font("宋体",Font.BOLD, 12));
		jb10.addActionListener(this);
		this.add(jb10);
		jb11=new JButton("下一个");
		jb11.setBounds(110, 270, 50, 40);
		jb11.setMargin(new Insets(0, 0, 0, 0));
		jb11.setFont(new Font("宋体",Font.BOLD, 12));
		jb11.addActionListener(this);
		this.add(jb11);
		jl10=new JLabel("按下标查询",JLabel.CENTER);
		jl10.setBounds(40, 320, 100, 60);
		jl10.setFont(new Font("宋体",Font.BOLD, 16));
		this.add(jl10);
		jt8=new JTextField();
		jt8.setBounds(65, 380, 50, 40);
		this.add(jt8);
		jb12=new JButton("OK");
		jb12.setBounds(115, 380, 35, 40);
		jb12.setMargin(new Insets(0, 0, 0, 0));
		jb12.setFont(new Font("宋体",Font.BOLD, 15));
		jb12.addActionListener(this);
		this.add(jb12);
		
		this.setLayout(null);
		this.setFocusable(true);		
		this.setBounds(300, 100, 500, 560);
		this.setVisible(true);		
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		length=0;
		if(x){
			ls=new LinkListService();
		}
		else{
			ls=new LinkListCircularService();
		}
				
		
		data=ls.insert(data, "123", length+1);
		data=ls.insert(data, "789", length+2);
		data=ls.insert(data, "234", length+3);
		data=ls.insert(data, "111", length+4);
		data=ls.insert(data, "qqq", length+5);
		jt1.setText(ls.getShow(data));
		length=ls.getLength();
		showdata=data;
		jt7.setText(showdata.value);		
	}
	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		if(e.getSource()==jb1){
			String str=jt2.getText();
			if(!"".equals(str)&&str!=null){
				data=ls.insert(data, str, 1);
				jt1.setText(ls.getShow(data));
				length=ls.getLength();
				showdata=data;
				jt7.setText(showdata.value);
			}else{
				JOptionPane.showMessageDialog(null, "请输入要插入的数据");
			}
		}
		if(e.getSource()==jb2){
			String str=jt2.getText();
			if(!"".equals(str)&&str!=null){
				data=ls.insert(data, str, length+1);
				jt1.setText(ls.getShow(data));
				length=ls.getLength();
				showdata=data;
				jt7.setText(showdata.value);
			}else{
				JOptionPane.showMessageDialog(null, "请输入要插入的数据");
			}
		}
		if(e.getSource()==jb3){
			String str=jt2.getText();
			try{
				int tag=Integer.parseInt(jt3.getText());
				if(tag>length+1||tag<1){
					JOptionPane.showMessageDialog(null, "输入范围:"+(length==0?"1":("1-"+(length+1))));
				}
				else if(!"".equals(str)&&str!=null){
					data=ls.insert(data, str, tag);
					jt1.setText(ls.getShow(data));
					length=ls.getLength();
					showdata=data;
					jt7.setText(showdata.value);
				}else{
					JOptionPane.showMessageDialog(null, "请输入要插入的数据");
				}
			}
			catch(Exception e1){
				JOptionPane.showMessageDialog(null, "请输入正确的下标");
			}			
		}
		if(e.getSource()==jb4){
			if(data!=null){
				data=ls.delete(data, 1);
				jt1.setText(ls.getShow(data));
				length=ls.getLength();
				showdata=data;
				jt7.setText(showdata==null?"":showdata.value);			
			}
			else{
				JOptionPane.showMessageDialog(null, "没有了");
			}
		}
		if(e.getSource()==jb5){			
			if(data!=null){
				data=ls.delete(data, length);
				jt1.setText(ls.getShow(data));
				length=ls.getLength();
				showdata=data;
				jt7.setText(showdata==null?"":showdata.value);
			}
			else{
				JOptionPane.showMessageDialog(null, "没有了");
			}
		}
		if(e.getSource()==jb6){			
			try{
				int tag=Integer.parseInt(jt4.getText()); 
				if(tag>length||tag<1){
					JOptionPane.showMessageDialog(null, "输入范围:"+(length==0?"没有了":("1-"+length)));
				}
				else{
					data=ls.delete(data, tag);
					jt1.setText(ls.getShow(data));
					length=ls.getLength();
					showdata=data;
					jt7.setText(showdata==null?"":showdata.value);
				}				
			}
			catch(Exception e1){
				JOptionPane.showMessageDialog(null, "请输入正确的下标");
			}
		}
		if(e.getSource()==jb7){
			if(data!=null){
				String str=jt5.getText();
				if(!"".equals(str)&&str!=null){
					ls.update(data, str, 1);
					jt1.setText(ls.getShow(data));
					length=ls.getLength();
					jt7.setText(showdata.value);
				}else{
					JOptionPane.showMessageDialog(null, "请输入要修改的数据");
				}
			}
			else{
				JOptionPane.showMessageDialog(null, "没有了");
			}
			
		}
		if(e.getSource()==jb8){
			
			if(data!=null){
				String str=jt5.getText();
				if(!"".equals(str)&&str!=null){
					ls.update(data, str, length);
					jt1.setText(ls.getShow(data));
					length=ls.getLength();
					jt7.setText(showdata.value);
				}else{
					JOptionPane.showMessageDialog(null, "请输入要修改的数据");
				}
			}
			else{
				JOptionPane.showMessageDialog(null, "没有了");
			}
		}
		if(e.getSource()==jb9){
			String str=jt5.getText();		
			try{
				int tag=Integer.parseInt(jt6.getText()); 
				if(tag>length||tag<1){
					JOptionPane.showMessageDialog(null, "输入范围:"+(length==0?"没有了":("1-"+length)));
				}
				else if(!"".equals(str)&&str!=null){
					ls.update(data, str, tag);
					jt1.setText(ls.getShow(data));
					length=ls.getLength();
					jt7.setText(showdata.value);
				}else{
					JOptionPane.showMessageDialog(null, "请输入要修改的数据");
				}
			}
			catch(Exception e1){
				JOptionPane.showMessageDialog(null, "请输入正确的下标");
			}
		}
		
		if(e.getSource()==jb10){                    
			if(showdata.previous!=null){
				showdata=showdata.previous;
				jt7.setText(showdata.value);
			}
			else{
				JOptionPane.showMessageDialog(null, "没有了");
			}			
		}
		if(e.getSource()==jb11){			
			if(showdata.next!=null){
				showdata=showdata.next;
				jt7.setText(showdata.value);
			}
			else{
				JOptionPane.showMessageDialog(null, "没有了");
			}
		}
		
		if(e.getSource()==jb12){
			try{
				int tag=Integer.parseInt(jt8.getText()); 
				if(tag>length||tag<1){
					JOptionPane.showMessageDialog(null, "输入范围:"+(length==0?"没有了":("1-"+length)));
				}
				else{
					showdata=data;
					for(int j=0;j<tag-1;j++){
						showdata=showdata.next;
					}
					jt7.setText(showdata.value);
				}				
			}
			catch(Exception e1){
				JOptionPane.showMessageDialog(null, "请输入正确的下标");
			}			
		}
	}
}

定义变量的时候懒了直接排的号,可后悔了,越往后越麻烦,这毛病可得改。

一开始写的时候构造函数是无参,后来打算加个参数来区别两种链表的时候在LinkListView.java里面new构造函数总是出错:The constructor ... is undefined。搜了好久又补了个无参的构造函数才正常,以后记住只要自定义构造函数了就得再写无参构造函数。

调整JButton大小的时候发现里面的字特小,尝试将字体变大但直接显示不出来了,明明空白部分还很多,后来找到了setMargin(new Insets(int top, int left, int bottom,int right))这个方法,设定标签旁边空白的大小。

实例化时直接生成一个链表,默认为"123,789,234,111,qqq"

JButton的监听器里面的if用的有点多,主要是保证输入数据的加以限制和规范。

LinkListData showdata的作用是让一个活动的节点对象起到查询的作用,每次数据操作后都需要让showdata=data来保证更新。

查找里面的下一个上一个按钮是为了体现出双向链表和循环链表的区别,毕竟不看代码只看界面只有这里能看出来了 - -!

 Java实现双向链表和循环链表_第1张图片

 

View已做好,接下来就是数据的处理了。

一、双向链表

public class LinkListService {
	//插入
	public LinkListData insert(LinkListData data,String value,int i){
		if(data==null){
			data=new LinkListData(value);
			return data;
		}
		else if(i==1){
			LinkListData begin=new LinkListData(value);
			begin.next=data;
			data.previous=begin;
			return begin;
			}
			else{
				LinkListData datafor = data;
				for(int j=0;j<i-2;j++){
					datafor=datafor.next;
				}
				LinkListData between=new LinkListData(value);
				if(datafor.next!=null){
					between.next=datafor.next;
					datafor.next.previous=between;
				}
				datafor.next=between;
				between.previous=datafor;
				return data;
			}
	}
	//删除
	public LinkListData delete(LinkListData data,int i){
		if(i==1){
			if(data.next!=null){
				data.next.previous=null;
				return data.next;
			}
			else{
				return null;
			}
		}
		else{
			LinkListData datafor = data;
			for(int j=0;j<i-2;j++){
				datafor=datafor.next;
			}
			if(datafor.next.next!=null)
				datafor.next.next.previous=datafor;
			datafor.next=datafor.next.next;			
			return data;
		}
	}
	//修改
	public void update(LinkListData data,String value,int i){
		for(int j=0;j<i-1;j++){
			data=data.next;
		}
		data.value=value;
	}
	//显示数据
	int length;
	public String getShow(LinkListData data){
		StringBuilder sb=new StringBuilder();
		length=0;
		if(data!=null){
			while(data!=null){
				length++;
				sb.append(data.value+",");
				data=data.next;
			}
			sb.deleteCharAt(sb.lastIndexOf(","));			
		}
		else
			sb.append("");
		return sb.toString();
	}
	public int getLength(){
		return length;
	}
}

双向链表需注意插入删除第一个节点的处理:

插入第一个时需先判断链表是否为空,然后将新节点的next指向原节点,原节点的previous指向新节点,return新节点;

删除第一个时需要判断链表是否只有一个节点,然后只需将头结点的next的previous改为null,return头结点next即可。

getShow(LinkListData data)这个方法在每次数据操作后都需要调用一次以保证数据列表的更新,需要注意的是链表为null是返回“”

在getShow(LinkListData data)执行的时候统计链表的长度保存到llength,所以每次调用完getShow(LinkListData data)后同时调用一下getLength()来更新长度,作用是输入指定下标时加以限制避免越界。

二、循环链表

public class LinkListCircularService extends LinkListService {
	public LinkListData insert(LinkListData data,String value,int i){
		if(data==null){
			data=new LinkListData(value);
			data.tag=1;
			data.next=data;
			data.previous=data;
			return data;
		}
		else if(i==1){
			LinkListData begin=new LinkListData(value);
			data.tag=0;
			begin.tag=1;
			begin.next=data;
			begin.previous=data.previous;
			data.previous.next=begin;
			data.previous=begin;
			return begin;
			}
			else{
				LinkListData datafor = data;
				for(int j=0;j<i-2;j++){
					datafor=datafor.next;
				}
				LinkListData between=new LinkListData(value);
				between.next=datafor.next;
				datafor.next.previous=between;
				datafor.next=between;
				between.previous=datafor;
				return data;
			}
	}
	//删除
	public LinkListData delete(LinkListData data,int i){
		if(i==1){			
			if(data.next.tag!=1){
				data.tag=0;
				data.next.tag=1;
				data.previous.next=data.next;
				data.next.previous=data.previous;
				return data.next;
			}
			else{
				return null;
			}
		}
		else{
			LinkListData datafor = data;
			for(int j=0;j<i-1;j++){
				datafor=datafor.next;
			}
			datafor.previous.next=datafor.next;
			datafor.next.previous=datafor.previous;		
			return data;
		}
	}
	//修改
	public void update(LinkListData data,String value,int i){
		for(int j=0;j<i-1;j++){
			data=data.next;
		}
		data.value=value;
	}
	//显示数据
	int length;
	public String getShow(LinkListData data){
		StringBuilder sb=new StringBuilder();
		length=0;
		if(data!=null){
			sb.append(data.value+",");
			length++;
			if(data.next.tag!=1){
				data=data.next;
				while(data.tag!=1){
					length++;
					sb.append(data.value+",");
					data=data.next;
				}	
			}
			sb.deleteCharAt(sb.lastIndexOf(","));
		}
		else
			sb.append("");
		return sb.toString();
	}
	public int getLength(){
		return length;
	}

}


循环链表是继承的双向链表,这样做的目的是在View中实例化两个类不用区分声明了,调用时也不用额外判断调用哪一个。

同样需要注意的是对头一个节点的操作时注意改变它的tag,当只有一个节点时data.next=data;data.previous=data;插入删除第一个时与对尾节点相连。

 

总结:代码不多才几百行,但是在写的时候还是有许多小细节导致卡壳了,很多基础知识发现很实用但是却还要去翻课本,java基础还是很不牢固,今后还是要多敲代码,只看理论无非是眼高手低!!

 

 

 

第一篇博客!!

你可能感兴趣的:(java,数据结构,链表,界面)