线性结构和非线性结构、稀疏数组、队列、链表

线性结构

一、线性结构是最常见的数据结构,特点是数据元素之间存在一对一的线性关系。

二、线性结构有两种不同的存储结构,即顺序存储结构和链式存储结)。顺序存储的线性表叫做顺序表,顺序中的存储元素是连续的;链式存储的线性表叫做链表,其中的存储元素不一定是连续的,元素结点中存放数据元素以及相邻元素的地址信息。

三、线性结构常见的有:数组,队列,链表和栈

非线性结构
非线性结构包括:二维数组,多维数组,广义表,树结构,图结构

稀疏数组

当一个数组大部分都为0,或者同一个值得数组时,可以用稀疏数组来保存该数组。
处理方法:
记录数组一共有几行几列,有多少个不同的
二维数组转稀疏数组的步骤
1、遍历原始的二维数组,得到有效数据的个数sum
2、根据sum就可以创建稀疏数组sparseArr int [sum+1][3]
3、将二维数组的有效数据存入到稀疏数组
稀疏数组转为原始二维数组的思路
1、先读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组。
2、在读取稀疏数组后几行的数据,并赋给原始的二维数组即可。

 public static void main(String[] args) {
	//创建一个原始的二位数组11*11
	  //0表示没有棋子,1表示黑子2,表示白子
	  int chessArr1[][]=new int[11][11];
	  chessArr1[1][2]=1;
	  chessArr1[2][3]=2;
   //输出原始的二维数组
	  for(int[]row :chessArr1) {
		  for(int data:row) {
			  System.out.printf("%d\t",data);
		  }
		  System.out.println();
	  }
   //将二维数组转为稀疏数组
   //1、先遍历二维数组得到非0数据的个数
	  int sum=0;
	  for(int i=0;i<chessArr1.length;i++) {
		  for(int j=0;j<chessArr1[0].length;j++) {
			  if(chessArr1[i][j]!=0) {
				  sum++;
			  }
		  }
	  }
	  System.out.println("sum"+sum);
	  //创建一个稀疏数组
	  int sparseArr1[][]=new int[sum+1][3];
	  //给稀疏数组赋值
	  //稀疏数组的第一行分别存放行数,列数,非0数据个数
	  sparseArr1[0][0]=11;
	  sparseArr1[0][1]=11;
	  sparseArr1[0][2]=sum;
	  //遍历二维数组,将非0的值放入稀疏数组中
	  int count=0;
	  for(int i=0;i<chessArr1.length;i++) {
		  for(int j=0;j<chessArr1[0].length;j++) {
			  if(chessArr1[i][j]!=0) {
				  count++;
				  sparseArr1[count][0]=i;
				  sparseArr1[count][1]=i;
				  sparseArr1[count][2]=chessArr1[i][j];
			  }
		  }
	  }
	  //输出稀疏数组
	  for(int[]row : sparseArr1) {
		  for(int data: row) {
			  System.out.printf("%d\t",data);
		  }
		  System.out.println();
	  }
	  //稀疏数组转为二维数组
	  //定义一个新数组,读取稀疏数组数据,从稀疏数组的第二行开始读取,不给二维数组即可
	  int chessArr2[][]=new int[sparseArr1[0][1]][sparseArr1[0][1]];
	  for(int i=1;i<sparseArr1.length;i++) {
		  chessArr2[sparseArr1[i][0]][sparseArr1[i][1]]=sparseArr1[i][2];
	  }
	  //输出转化后的二维数组
	  System.out.println("转化后的二维数组");
	  for(int [] row :chessArr2) {
		  for(int data:row) {
			  System.out.printf("%d\t",data);
		  }
		  System.out.println();
	  }
	  }

队列

队列是一个有序列表,可以用数组或者是链表来实现
遵循先入先出的原则,即:先存入队列的数据,要先取出。后存入的要后去除
队列本身是有序列表,若使用数组的结构来存储队列的数据。则队列数组的声明如下图,其中maxsSize是该队列的最大容量
因为队列的输出,输入分别是从前端和后端来处理的,因此需要两个变量front及rear分别记录队列前后端的下表,front会随着数据输出而改变,而rear则是随着数据输入而改变


链表

1、链表是以节点的方式来储存,是链式存储
2、每个节点包含data域,next域(指向下一个节点)
3、链表的各个节点不一定是连续储存
4、链表分为带头节点的链表和头节点的链表,根据实际的需求来确定

单链表

public static void main(String[] args) {
    //		创建节点
 		HeroNode hero1=new HeroNode(1, "lhg", "前端");
 		HeroNode hero2=new HeroNode(2, "wyf", "java后端");
 		HeroNode hero3=new HeroNode(3, "ljk", "python");
 		HeroNode hero4=new HeroNode(4, "lmy", "Unity");
 		//创建单链表
 		SinlLinkedList list=new SinlLinkedList();
 		//按顺序添加节点
// 		list.add(hero1);
// 		list.add(hero2);
// 		list.add(hero3);
// 		list.add(hero4);
 		System.out.println("乱序插入节点 ");
 		list.addOrder(hero3);
 		list.addOrder(hero4);
 		list.addOrder(hero1);
 		list.addOrder(hero2);
 		list.List();
 		System.out.println("修改节点");
 		HeroNode newhero=new HeroNode(4, "girl","C#");
 		list.update(newhero);
 		//显示单链表
 		list.List();
 		System.out.println("删除1");
 		list.delete(1);
 		list.List();
	}
class SinlLinkedList {
	 private HeroNode head=new HeroNode(0, "", "");
	 //添加结点到单向链表
	 //1.找到当前链表的最后结点
     //2.将最后这个结点的next指向新的结点
	 public void add(HeroNode heroNode) {
	  //因为head不能动,因此我们要遍历一个辅助遍历temp
		 HeroNode temp=head;
		 while(true) {
			 if(temp.next==null) {
				 break;}
			 //指向新的结点
			 temp=temp.next;
		 }
		 temp.next=heroNode;
	}
	 //按照编号插入节点
	 public void addOrder(HeroNode heroNode) {
		 boolean flag=false;
	     HeroNode temp=head;
	      while(true) {
	    	 if(temp.next==null) {  //说明temp已经在链表的最后,可以添加
	    		 break;
	    	 } 
	    	 if(temp.next.no>heroNode.no) {//说明heroNode处于temp和temp.next之间,可以添加
	    		break;
	    	 }else if(temp.next.no==heroNode.no) {   //说明该添加的编号已经存在,不可以添加
	    		  flag=true;		 
	    		  break;
	    	 }
	    	 temp=temp.next;  //节点后移
	      }
	      if(flag==true) {
	    	  System.out.println("已经存在"+heroNode.no);
	      }else {
	    	  //插入链表之中
	    	  heroNode.next=temp.next;
	    	  temp.next=heroNode;
	      }
	}
	 //修改节点
	 public void update(HeroNode heroNode) {
		 //判断是否为空
		 if(head.next==null) {
			 System.out.println("链表为空");
			 return;
		 }
		 //定义一个辅助变量temp
		 HeroNode temp=head;
		 boolean flag = false;
		 while(true) {
			 if(temp.next==null) {   //遍历完毕
				 break;       
			 }
			 if(temp.next.no==heroNode.no) {
				 flag=true;
				 break;
			 }
			 temp=temp.next;
		 }
		 if(flag) {
			 temp.next.name=heroNode.name;
			 temp.next.nickname=heroNode.nickname;
		 }else {
			 System.out.println("没有找到");
		 }
	 }
	 //删除节点
	 public void delete(int no) {
		 HeroNode temp=head;
		 boolean flag=false;
		 while(true) {
			 if(temp.next==null) {  //遍历完毕
				 break;   
			 }
			 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("链表为空");
		 }
		 HeroNode temp=head.next;
		 while (true) {
			 //判断是否到链表的最后
			 if(temp==null) {
				 break;
			 }
			 System.out.println(temp);
			 //temp后移
			 temp=temp.next;
		 }
	 }
}
//定义HeroNode,每个HeroNode就是一个结点
class HeroNode{
	public int no;
	public  String name;
	public String nickname;
	 public HeroNode next;   //指向下一个结点
	 //构造器
	 public HeroNode(int no, String name,String nickname) {
		 this.no=no;
		 this.name=name;
		 this.nickname=nickname;
	 }
	 //显示,重写toString方法
	 public String toString(){
		 return "HeroNode[no="+no+",name="+name+",nickname="+nickname+"]";
	 }
	 
}

双向链表

public static void main(String[] args) {
		// TODO Auto-generated method stub
		HeroNode2 hero1=new HeroNode2(1, "lhg", "前端");
 		HeroNode2 hero2=new HeroNode2(2, "wyf", "java后端");
 		HeroNode2 hero3=new HeroNode2(3, "ljk", "python");
 		HeroNode2 hero4=new HeroNode2(4, "lmy", "Unity");
        DoubleLinkList list=new DoubleLinkList();
        list.add(hero1);
        list.add(hero2);
        list.add(hero3);
        list.add(hero4);
        System.out.println("添加打印输出");
        list.show();
        System.out.println("修改最后一个节点");
        HeroNode2 newhero=new HeroNode2(4, "aaaa", "Usdasdasdas");
        list.update(newhero);
        list.show();
        System.out.println("删除最后一个节点");
        list.delete(4);
        list.show();
	}

class DoubleLinkList{
	//先初始化一个头结点,头节点不要动,不存放具体的数据
	private HeroNode2 head=new HeroNode2(0, "", "");
	//返回头节点
	 public HeroNode2 getHead() {
		 return head;
	 }
	 //遍历双向链表
	 public void show() {
		 if(head.next==null)System.out.println("链表为空");
		 HeroNode2 temp=head.next;
		 while (true) {
			 if(temp==null)break;  //判断是否到最后
			 System.out.println(temp);
			 temp=temp.next;
		 }
	 }
	 //添加结点
	 public void add(HeroNode2 heroNode2) {
		 HeroNode2 temp=head;
		 while(true) {
			 if(temp.next==null)break;
			 temp=temp.next;
		 }
		 temp.next=heroNode2;
		 heroNode2.pre=temp;
	 }
	 //修改节点
	 public void update(HeroNode2 heroNode2) {
		 if(head.next==null) {
			 System.out.println("链表为空");
			 return;
		 }
		 HeroNode2 temp=head;
		 boolean flag=false;
		 while(true) { 	
			 if(temp.next.no==heroNode2.no) {
				 flag=true;
				 break;
			 }
			 temp=temp.next;
		 }
		 if(flag) {
			 temp.next.name=heroNode2.name;
			 temp.next.nickname=heroNode2.nickname;
		 }else{
			 System.out.println("没有找到该节点");
		 }
	 }
	 //删除节点
	 public void delete(int no) {
		 if(head.next==null) {
			 System.out.println("输入为空");
			 return;
		 }
		 HeroNode2 temp=head.next;
		 boolean flag=false;
		 while(true){
			 if(temp==null) break;
			 if(temp.no==no){
				 flag=true;
				 break;
		  }
			 temp=temp.next;
		 }
		 if(flag) {
			 temp.pre.next=temp.next;
			 if(temp.next!=null) {
				 temp.next.pre=temp.pre;
			 }
		 }
	 }
}


//定义双向链表
class HeroNode2{
	 public int no;
	 public String name;
	 public String nickname;
	 public HeroNode2 next;   //指向下一个节点
	 public HeroNode2 pre;   //指向前一个节点
//	 构造器
	 public HeroNode2(int no,String name,String nickname) {
		 this.no=no;
		 this.name=name;
		 this.nickname=nickname;	 
	 }
	 //显示,重写toString方法
	 public String toString(){
		 return "HeroNode2[no="+no+",name="+name+",nickname="+nickname+"]";
	 }
	 
}

单向环形列表

构建一个环形链表的思路
1.先创建第一个节点,让first指向该节点,并形成环形
2.后面每创建一个新的节点,就把该节点,加入到已有的环形链表中即可
遍历环形链表
1.先让一个辅助指针,指向first节点
2.然后通过一个while循环遍历该环形链表即可

  public static void main(String[] args) {
	CircleSingleLinkedList list=new CircleSingleLinkedList();
	list.add(5);
	list.showBoy();
}

class CircleSingleLinkedList {
	//创建一个first节点,当前没有标号
    private Boy first=new Boy(-1);
    //添加小孩节点,构建成一个环形的链表
    public void add(int nums) {
		//nums 做一个数据校验
    	if(nums<1) {
    		System.out.println("nums的值不正确");
    	} 
    	Boy curBoy=null;   //辅助指针,帮助构建环形链表
    	for(int i=1;i<=nums;i++) {
    		Boy boy=new Boy(i);
    		if(i==1) {           //第一个初始化
    			first=boy;
    			first.setNext(first);
    			curBoy=first;
    		}else {
    			curBoy.setNext(boy); //curBoy指向下一个
    			boy.setNext(first);  //刚添加的节点指向第一个
    			curBoy=boy;
    		}
    	}	
	}
  //遍历当前的环形列表
	public void showBoy() {
		//判断链表是否为空
		if(first==null) {
	        System.out.println("链表为空");
	        return;
		}
		Boy curBoy=first;
		while(true) {
			System.out.printf("小孩的编号%d\n",curBoy.getNo());
			if(curBoy.getNext()==first) {
				break;
			}
			curBoy=curBoy.getNext();
		}
	}
    
}
class  Boy{
	private int no ;//编号
	private Boy next; //指向下一个
	public Boy (int no) {
		this.no=no;
	}
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
	   this.no=no;
	}
	public Boy getNext() {
		return next;
	}
	public void setNext(Boy boy) {
		this.next=boy;
	}
	
}

约瑟夫环
思路一:
一、需求创建一个辅助指针(变量)helper,事先应该指向环形链表的最后这个节点
二、报数时,helper和first指针同时移动m-1次
三、first指向的人出圈

first=first.next;
helper.next=first;

具体代码

public static void main(String[] args) {
	CircleSingleLinkedList list=new CircleSingleLinkedList();
	list.add(5);
	list.showBoy();
	list.countBoy(1, 2, 5);
}

class CircleSingleLinkedList {
	//创建一个first节点,当前没有标号
    private Boy first=new Boy(-1);
    //添加小孩节点,构建成一个环形的链表
    public void add(int nums) {
		//nums 做一个数据校验
    	if(nums<1) {
    		System.out.println("nums的值不正确");
    	} 
    	Boy curBoy=null;   //辅助指针,帮助构建环形链表
    	for(int i=1;i<=nums;i++) {
    		Boy boy=new Boy(i);
    		if(i==1) {           //第一个初始化
    			first=boy;
    			first.setNext(first);
    			curBoy=first;
    		}else {
    			curBoy.setNext(boy); //curBoy指向下一个
    			boy.setNext(first);  //刚添加的节点指向第一个
    			curBoy=boy;
    		}
    	}	
	}
  //遍历当前的环形列表
	public void showBoy() {
		//判断链表是否为空
		if(first==null) {
	        System.out.println("链表为空");
	        return;
		}
		Boy curBoy=first;
		while(true) {
			System.out.printf("小孩的编号%d\n",curBoy.getNo());
			if(curBoy.getNext()==first) {
				break;
			}
			curBoy=curBoy.getNext();
		}
	}
	//计算小孩出圈的顺序
    //starNo表示从第几个人开始数
	//countNum表示数几下
	//nums表示最初有多少个人在圈中
	public void countBoy(int startNo,int countNum,int nums) {
		if(startNo<1||startNo>nums||first==null) {
			System.out.println("输入错误");
			return;
		}
		Boy helper=first;        //辅助指针
		while(true) {            //helper指向尾指针
			if(helper.getNext()==first) {
				break;
			}
			helper=helper.getNext();
		}
		//第一次报数之前,first和helper移动starNo-1次
		for(int i=1;i<startNo;i++) {
			helper=helper.getNext();
			first=first.getNext();
		}
		//循环操作,直至剩下一人
		while (true) {
			if(first==helper) {
				break;
			}
			for(int j=0;j<countNum-1;j++) {
				first=first.getNext();
				helper=helper.getNext();
			} 
			System.out.printf("出圈人员编号%d\n",first.getNo());
			first=first.getNext();
			helper.setNext(first);
		}
		System.out.printf("最终留在圈中的编号%d\n",first.getNo());
		
	}
    
}
class  Boy{
	private int no ;//编号
	private Boy next; //指向下一个
	public Boy (int no) {
		this.no=no;
	}
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
	   this.no=no;
	}
	public Boy getNext() {
		return next;
	}
	public void setNext(Boy boy) {
		this.next=boy;
	}
	
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李和贵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值