数据结构(一)线性链表、非线性链表、稀疏数组与队列、单向链表

数据结构(一)线性链表、非线性链表、稀疏数组与队列、单向链表数据结构和算法的关系 数据 data 结构 structure 是一门研究组织数据方式的学科 有了编程语言也就有了数据结构 学好数据结构可以编写出更加漂亮更加有效率的代码 要学习好数据结构就要多多考虑如何将生活中遇到的问题 用程序去实现解决 程序 数据结构 算法 数据结构是算法的基础 换言之 想要学好算法 需要把数据结构学到位 线性链表和非线性链表数据结构包括 线性结构和非线性结构 线性结构 1 线性结构作为最常用的数据结构 其特点是数据元素之间存在对的线性关系 a 0 3

数据结构

数据结构分为逻辑结构和物理结构

在这里插入图片描述

逻辑结构

 逻辑结构:是指数据对象中数据元素之间的相互关系。其实这也是我们今后最需要关注的问题。逻辑结构分为以下四种:

1.集合结构:

2 线性结构:

3.树状结构:

4.图形结构:

物理结构:

数据结构和算法的关系

线性链表和非线性链表

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

稀疏数组和队列

稀疏Sparsearray数组

在这里插入图片描述基本介绍
当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组。
稀疏数组的处理方法是: .
1)记录数组一共有几行几列,有多少个不同的值
2)把具有不同值的元素的行列及值记录在一个小规模的数组中,从而缩小程序的规模
在这里插入图片描述右图的第一行【0】的6是一共6行,7一共7列,8指一共8个值
原来的数组是67=42大小的数组,可以将其变成93=27的稀疏数组












在这里插入图片描述代码实现:

public class Sparcesearray { 
    public static void main(String[] args) { 
    //第一步 创建一个11*11的二维数组 //给二维数组中添加棋子 //1 表示黑子,2表示蓝色的,0表示没有棋子 int cheersArray[][] = new int[11][11]; cheersArray[1][2] =1; cheersArray[2][3] =2; cheersArray[4][5] =2; for (int[] ints : cheersArray) { 
    for (int i : ints) { 
    System.out.print("\t"+i); } System.out.println(); } // 获取二维数组中元素不为0的个数 sum int sum=0; for (int i = 0; i < 11; i++) { 
    for (int j = 0; j < 11; j++) { 
    if (cheersArray[i][j]!=0){ 
    sum++; } } } System.out.println("sum个数是"+sum); //创建稀疏数组 int specArray[][] =new int[sum+1 ][3]; specArray[0][0] =11; specArray[0][1] =11; specArray[0][2] =sum; //将二维数组中不为0的数放入到稀疏数组中去 int count=0; for (int i = 0; i < 11; i++) { 
    for (int j = 0; j < 11; j++) { 
    if (cheersArray[i][j]!=0){ 
    count++; specArray[count][0]=i; specArray[count][1]=j; specArray[count][2]=cheersArray[i][j]; } } } System.out.println("二维数组变成的稀疏数组是:"); for (int[] ints : specArray) { 
    for (int anInt : ints) { 
    System.out.print("\t"+anInt); } System.out.println(); } System.out.println("稀疏数组再次变为原来的二维数组是"); //第三步将稀疏数组再次变成二维数组 int cheersArray2[][] =new int[specArray[0][0]] [specArray[0][1]]; //将稀疏数组中的值再次赋值给二维数组(循环从1开始,因为稀疏数组从第二行开始才是值) for (int i = 1; i <specArray.length ; i++) { 
    cheersArray2[specArray[i][0]][specArray[i][1]] =specArray[i][2]; } for (int[] ints : cheersArray2) { 
    for (int anInt : ints) { 
    System.out.print("\t"+anInt); } System.out.println(); } } } 

队列

//使用数组模拟队列 public class ArrayQueue { 
    private int maxSize;//队列最大的大小 private int front;//指向队列的头 private int real;//指向队列的尾部 private int array[];//该数组用于数据的存储,模拟队列的存取 //创建队列的构造器 public ArrayQueue(int arraymaxSize){ 
    maxSize=arraymaxSize; array=new int[maxSize]; front=-1;//指向队列头部的前一个位置 real=-1;//指向队列尾部的数据(可能是队列最后一个数据) } //是否是满的 public Boolean isFull(){ 
    return real ==maxSize-1; } //是否是空的 public Boolean isEmpty(){ 
    return front==real; } //向队列中添加数据 public void addQueue(int n){ 
    if (isFull()){ 
    System.out.println("对不起队列满了不能加入数据"); return; } real++;//尾部后移 array[real]=n; } public int getQueue(){ 
    if (isEmpty()){ 
    throw new RuntimeException("对不起,队列没有数据可取"); } front++;//让front后移 return array[front]; } //显示所有的队列数据 public void list(){ 
    if (isEmpty()){ 
    System.out.println("队列中没有数据,请先插入数据"); } for (int i = 0; i <array.length ; i++) { 
    System.out.println(+array[i]); } } //查看队列头部的数据 public int peak(){ 
    if (isEmpty()){ 
    throw new RuntimeException("队列中,没有数据请先插入数据"); } return array[front+1]; } public static void main(String[] args) { 
    ArrayQueue queue = new ArrayQueue(3); Boolean loop=true; char key =' '; Scanner scanner = new Scanner(System.in); while(loop){ 
    System.out.println("s(show) :显示对列"); System.out.println("e(exit) :退出对列"); System.out.println("a(add) :添加对列"); System.out.println("g(get) :获取对列的值"); System.out.println("h(head) :查看队列头部的值"); key= scanner.next().charAt(0); switch (key){ 
    case 's': queue.list(); break; case 'e': scanner.close(); loop=false; break; case 'a': System.out.println("请输入一个数字"); int value =scanner.nextInt(); queue.addQueue(value); break; case 'g': try{ 
    int res =queue.getQueue(); System.out.println("取出的数据是"+res); }catch (Exception e){ 
    e.printStackTrace(); } break; case 'h': try { 
    int head = queue.peak(); System.out.println("查看头部的数据是"+head); }catch (Exception e){ 
    e.printStackTrace(); } break; default:break; } } System.out.println("程序退出"); } } 

数组模拟环形队列

class CircleArray{ 
    int maxSize;//队列最大的大小 //front指向队列的第一个元素 //front=0; int front;//指向队列的头 //real指向队列最后一个元素的下一个位置 //real=0; int real;//指向队列的尾部 private int array[];//该数组用于数据的存储,模拟队列的存取 public CircleArray(int arrymaxSize){ 
    maxSize=arrymaxSize; array=new int[maxSize]; } //是否是满的 public Boolean isFull(){ 
    return ( real +1) % maxSize==front; } //是否是空的 public Boolean isEmpty(){ 
    return front==real; } //向队列中添加数据 public void addQueue(int n){ 
    if (isFull()){ 
    System.out.println("对不起队列满了不能加入数据"); return; } array[real]=n; real=(real+1) % maxSize; } //从队列中取出数据 public int getQueue(){ 
    if (isEmpty()){ 
    throw new RuntimeException("对不起,队列没有数据可取"); } //这里我们分析到front指向的默认是第一个元素 //第一步先将array【front】取出,保存在临时变量里 //第二步front后移 //第三步返回临时的变量 int value= array[front]; front=(front+1)%maxSize; return value; } //显示所有的队列数据 public void list(){ 
    if (isEmpty()){ 
    System.out.println("队列中没有数据,请先插入数据"); } for (int i = front; i <front+numbers() ; i++) { 
    System.out.println("循环队列的数据是:"+i%maxSize+array[i]); } } //计算出当前有效数据的个数 public int numbers(){ 
    return (real+maxSize-front)%maxSize; } //查看队列头部的数据 public int peak(){ 
    if (isEmpty()){ 
    throw new RuntimeException("队列中,没有数据请先插入数据"); } return array[front]; } public static void main(String[] args) { 
    CircleArray queue = new CircleArray(3); Boolean loop=true; char key =' '; Scanner scanner = new Scanner(System.in); while(loop){ 
    System.out.println("s(show) :显示对列"); System.out.println("e(exit) :退出对列"); System.out.println("a(add) :添加对列"); System.out.println("g(get) :获取对列的值"); System.out.println("h(head) :查看队列头部的值"); key= scanner.next().charAt(0); switch (key){ 
    case 's': queue.list(); break; case 'e': scanner.close(); loop=false; break; case 'a': System.out.println("请输入一个数字"); int value =scanner.nextInt(); queue.addQueue(value); break; case 'g': try{ 
    int res =queue.getQueue(); System.out.println("取出的数据是"+res); }catch (Exception e){ 
    e.printStackTrace(); } break; case 'h': try { 
    int head = queue.peak(); System.out.println("查看头部的数据是"+head); }catch (Exception e){ 
    e.printStackTrace(); } break; default:break; } } System.out.println("程序退出"); } } 

链表(Linked List)

package com.zy.LinkedList; / * Created by MR.ZHANG on 2020/8/6 20:06 */ public class SingleLikedList { 
    //先初始化一个头节点,头节点不要动,不方具体的数据 private HereNode head =new HereNode(0,"",""); //添加节点到单向链表 //思路当不考虑编号顺序时, //1.找到当前链路的节点, //将最后节点的next指向新的节点 public void add(HereNode hereNode){ 
    //因为头节点不能动,所以我们需要一个临时temp去协助遍历 HereNode temp=head; //遍历链表找到最后 while(true){ 
    if (temp.next==null){ 
    break; } //如果没有找到,就将temp后移到下一个节点 temp = temp.next; } //当退出while循环时就表示,temp指向了链表的尾部 //将最后节点的next指向新的节点 temp.next=hereNode; } //第二种添加英雄的方法,按照排名插入 //如果插入的排名已经存在就不能插入成功,并返回一定的提示信息 public void addHereByOder(HereNode hereNode){ 
    //因为头节点不能动,所以我们需要辅助变量帮助我们遍历 //因为是单链表所以temp指向的是要插入结点的前一个节点 HereNode temp =hereNode; Boolean flag =false;//设置英雄是否存在,默认不存在 while(true){ 
    if (temp.next==null){ 
    //表示已经再链表的结尾 break; } if (temp.next.no>hereNode.no){ 
   //找到了可以插入的位置 break; }else if (temp.next.no==hereNode.no){ 
    flag=true;//说明已经存在 break; } temp=temp.next; } if (flag){ 
    System.out.println("角色已存在,插入失败"); }else{ 
    //插入到链表中,temp的后面 hereNode.next=temp.next; temp.next=hereNode; } } //修改节点信息,根据编号修改,不能修改编号只能修改节点的数据 public void update(HereNode newHereNode){ 
    if (head.next==null){ 
    System.out.println("链表为空"); return; } HereNode temp = head.next; boolean flag =false;//表示是否找到 while(true){ 
    if (temp==null){ 
    //表示已经遍历完了链表 break; } if (temp.no==newHereNode.no){ 
    //找到了 flag=true; break; } temp =temp.next; } if (flag){ 
    temp.name=newHereNode.name; temp.nickName=newHereNode.nickName; }else { 
    System.out.println("没有找到角色"); } } //删除链表的某一个节点 public void delete(int no){ 
    HereNode temp =head;//temp是待删除节点的上一个节点 Boolean flag =false;//判断待删除节点是否存在 while(true){ 
    if (temp.next==null){ 
   //已经到了链表的最后 break; } if (temp.next.no==no){ 
    flag=true; break; } temp=temp.next;//temp后移,这样我们才能完成循环遍历 } if (flag){ 
    temp.next=temp.next.next;//让找到的节点指向它下一个节点的下一个节点,这样没人指向它的时候,就会被GC回收掉 return; }else { 
    System.out.println("不好意思,没有找到想过要被删除的节点"); } } //查询链表集合 public void list(){ 
    //判断链表是否为空 if (head.next==null){ 
    System.out.println("链表没有数据无法遍历"); return; } //不为的情况下在再遍历输出链表数据 //因为头节点不能动,所以我们需要辅助变量来帮助我们遍历 HereNode temp =head; while(true){ 
   //判断是否走到了链表的尾部 if (temp==null){ 
    break; } System.out.println(temp); //将temp后移 否则会陷入死循环 temp =temp.next; } } } class HereNode { 
    public int no; public String name; public String nickName; public HereNode next; public HereNode(int no, String name, String nickName) { 
    this.no = no; this.name = name; this.nickName = nickName; } @Override public String toString() { 
    return "HereNode{" + "no=" + no + ", name='" + name + '\'' + ", nickName='" + nickName + '\'' + '}'; } } class test{ 
    public static void main(String[] args) { 
    HereNode hereNode1 = new HereNode(1, "宋江", "及时雨"); HereNode hereNode2 = new HereNode(2, "卢俊义", "玉麒麟"); HereNode hereNode3 = new HereNode(3, "吴用", "智多星"); HereNode hereNode4 = new HereNode(4, "林冲", "豹子头"); //加入到单向链表中 SingleLikedList list = new SingleLikedList(); list.add(hereNode1); list.add(hereNode2); list.add(hereNode3); list.add(hereNode4); // list.addHereByOder(hereNode1); // list.addHereByOder(hereNode4); // list.addHereByOder(hereNode2); // list.addHereByOder(hereNode3); list.list(); //测试更新 HereNode node = new HereNode(2, "小卢", "玉麒麟~~"); list.update(node); //测试删除 list.delete(1); System.out.println("删除后的节点情况"); list.list(); } } 

单链表面试题(新浪、百度、腾讯)

1)求单链表中有效节点的个数

public int getLength(HereNode head){ 
    if (head.next == null){ 
    return 0; } int length = 0; //定义一个辅助的temp 指向头节点的下一个节点,因为头节点没有有效数据 HereNode cur =head.next; while(cur !=null){ 
    length++; cur=cur.next; } return length; } 

获取单链表中倒数第k个节点

 //查询单链表中倒数第k个节点 //思路:编写一个方法接收head节点,同时接收index //index表示倒数第index节点 //先把链表从头到尾遍历出来,得到链表总长度getlenth() //得到size以后就可以遍历(size-index)个 //如果找到了就返回节点否则就返回未找到 public HereNode findLastIndexNode(HereNode head ,int index){ 
    //如果链表为空,我们就返回一个null即可 if (head.next==null){ 
    return null; } //第一个遍历得到链表长度,即节点的个数 int size = getLength(head); //第二次遍历,size-index就是我们要找的倒数第k个节点 //先做index的校验 if (index<=0||index>size){ 
    return null; } //定义辅助变量cur,for循环定位到倒数的index HereNode cur = head.next; for (int i = 0; i <size-index ; i++) { 
    cur =cur.next; } return cur; } 
 //将单链表的节点翻转形成新的单链表 public static void reserveList(HereNode head){ 
    //判断,当前链表为空或者当前链表只有一个节点时不用翻转直接输出 if(head.next==null||head.next.next==null){ 
    return; } //定义一个辅助的指针帮助我们去遍历原来的链表 HereNode cur= head.next; HereNode next =null;//指向当前节点的下一个节点 HereNode reverseNode = new HereNode(0,"",""); //遍历原来的列表,并从头遍历原来的链表,将遍历出来的节点依次放入到reverseNode最前端; while(cur!=null){ 
    next=cur.next;//保存当前节点下一个节点,后面会用到 cur.next=reverseNode.next;//将cur的下一个节点指向新的链表的最前端 reverseNode.next=cur; cur=next;//让cur不断的后移 } //将head。next指向reverseNode.next,从而实现了单链表的反转 head.next=reverseNode.next; } 

从尾到头打印链表

/将单向链表从尾到头打印出来 //逆序打印单链表 public void reversePrint(HereNode head) { 
    if (head.next==null){ 
    return;//链表空直接返回 } //创建一个栈,将单向链表的数据都压入栈中 Stack<HereNode> stack = new Stack<>(); HereNode cur =head.next; while(cur!=null){ 
    stack.push(cur); cur=cur.next; } //将栈中数据弹出 while (stack.size()>0){ 
    System.out.println(stack.pop());//stack栈的特点是先进后出 } } 
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/220460.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月17日 下午8:25
下一篇 2026年3月17日 下午8:26


相关推荐

  • 安装keil5(MDK)及导入pack包教程

    安装keil5(MDK)及导入pack包教程首先说明的是我安装的Keil版本为KeilV5.29.0.01、安装软件右键管理员权限运行安装包设置安装路径以及pack的存放路径随意输入FirstName和E-mail安装驱动完成软件安装,然后可以先关闭弹出的PackInstall(一会再添加)2、激活一下软件打开桌面的KeilFile→LicenseManagement(我之前注册过了)右…

    2022年5月27日
    2.0K
  • python安装不了whl文件_python whl文件怎么安装

    python安装不了whl文件_python whl文件怎么安装1 了解自己的 Python 版本的 方便后续下载合适的 whl 文件 win R 进入命令运行窗口 输入 cmd 打开命令提示符 接着输入 python 即可这是我的版本 3 7 1 win322 选择需要的 whl 文件下载 https www lfd uci edu gohlke pythonlibs 我的是 64 位所以选择的是 mysqlclient 1 4 2 cp37 cp37m win amd64 wh

    2026年3月26日
    3
  • clearTimeout() 方法

    clearTimeout() 方法定义和用法 clearTimeout 方法可取消由 setTimeout 方法设置的 timeout clearTimeout id of settimeout id of setinterval 由 setTimeout 返回的 ID 值 该值标识要取消的延迟执行代码块 eg lt html gt lt head gt lt scripttype

    2026年3月17日
    2
  • stl库使用_餐厅库管年终总结个人总结

    stl库使用_餐厅库管年终总结个人总结1、STL库的含义STL(StandardTemplateLibrary),即标准模板库,是一个具有工业强度的,高效的C++程序库。2、STL的好处STL作为一种标准,便于交流,掌握它,一方面可以让你写的程序,易于让别人理解,另一方面你也能够比较容易地理解别人写的程序。3、STL的关键概念要使用STL,要了解以下几个基本概念:容器:可以把它理解为存放数据的地方,常用的一些容器有链表(list)栈(stack)动态数组(vector…

    2022年10月15日
    5
  • 【西安xxx面经】

    【西安xxx面经】我是在线下一天面完的,总共有五面。一面:自我介绍,问题基本上都是根据简历上问的,我简历上写了算法和数据结构所以问题都是和这些相关。一面有两个面试官,先问了面向对象的思想,面向对象的三大特性,分别解释一下。然后就是数据结构方面的知识:栈,队列,哈希表,如果数据很多的话用哈希表怎么存储。手撕二分,然后手撕一个关于链表的题:现在有很多节点,每个节点都有它在链表中的编号,现在要按照编号将这个链表复原。(因为面试官没有c++环境,所以我用的记事本编程,需要讲出来思路,每一句的作用)。面试体验:两个面试官还是有压力

    2022年5月15日
    33
  • C++标准库之 Lower_Bound, upper_Bound

    C++标准库之 Lower_Bound, upper_Bound

    2021年11月30日
    50

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号