一、线性结构和非线性结构

线性结构:

1)线性绪构作为最常用的数据结构,其特点是数据元素之间存在一对一的线性关系

2)线性结构有两种不同的存储结构,即顺序存储结构和链式存储结构。顺序存储的
线性表称为顺序表,顺序表中的存储元素是连续的
3)链式存储的线性表称为链表,链表中的存储元素不一定是连续的,元素节点中存
放数据元素以及相邻元素的地址信息
4)线性结构常见的有:数组、队列、链表和栈,后面我们会详细讲解.

非线性结构:

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

二、稀疏数组

基本介绍:当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组。

稀疏数组的处理方法是:
1)记录数组一共有几行几列,有多少个不同的值
2)把具有不同值的元素的行列及值记录在一个小规模的数组中,从而缩小程序的规模

//实现原始数组和稀疏数组的相互转换;并存入文件进行保存和读取
package com.zjl.sparsearray; import java.io.*; public class SparseArray {
public static void main(String[] args) throws IOException {
String file = "C:\\Users\\wenman\\Desktop\\test\\sapraseArr.txt";
//定义一个原始的数组arr[11][11],并赋值arr[1][2] = 1, arr[2][3] = 2
int[][] arr = new int[11][11];
arr[1][2] = 1;
arr[2][3] = 2;
arr[3][4] = 2; //查看原始数据
for (int[] arr_:arr) {
for (int num:arr_) {
System.out.printf("%d ",num);
}
System.out.println();
}
//获取原始数据中的数据个数
int nums = 0;
for (int[] arr_:arr) {
for (int num:arr_) {
if (num != 0){
nums++;
}
}
} //将原始数组转变为稀疏数组
int[][] sparseArr = new int[nums + 1][3];
sparseArr[0][0] = 11;
sparseArr[0][1] = 11;
sparseArr[0][2] = nums;
int count = 0; for (int i = 0; i < 11; i++) {
for (int j = 0; j < 11; j++) {
if (arr[i][j] != 0){
count++;
sparseArr[count][0] = i;
sparseArr[count][1] = j;
sparseArr[count][2] = arr[i][j];
}
}
}
/**
* 将稀疏数组存入到文件中
*/
FileWriter fileWriter = new FileWriter(file);
for (int i = 0;i<sparseArr.length;i++) {
fileWriter.write(sparseArr[i][0]+" "+sparseArr[i][1]+" "+sparseArr[i][2]+"\n");
}
fileWriter.close(); //输出稀疏数组结构
for (int[] arr_:sparseArr) {
for (int num:arr_
) {
System.out.printf("%d ",num);
}
System.out.println();
} /**
* 从文件中读取数组
*/
BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
String line = null;
int lineNum = 0;
//初始化原始数组
String[] s = bufferedReader.readLine().split(" ");
int[][] arrs = new int[Integer.parseInt(s[0])][Integer.parseInt(s[1])];
//获取原始数组中的值并赋值
while ((line = bufferedReader.readLine())!=null) {
String[] s1 = line.split(" ");
arrs[Integer.parseInt(s1[0])][Integer.parseInt(s1[1])] = Integer.parseInt(s1[2]);
}
bufferedReader.close(); //将稀疏数组变成原始数组
// int[][] arrs = new int[sparseArr[0][0]][sparseArr[0][1]];
// for (int i = 1 ; i < sparseArr.length; i ++) {
// arrs[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
// }
for (int[] arr_:arrs) {
for (int num:arr_) {
System.out.printf("%d ",num);
}
System.out.println();
} }
}

 

三、队列

介绍:

1、队列是一个有序列表,可以用数组或者链表来实现,

2、遵循先入先出的原则。即:先存入队列的数据,要先取出。后存入的要后取出

用数组模拟:

在入队和出队时:

因为队列的输出、输入是分别从前后端来处理,因此需要两个变量front及rear分别记录队列前后端的下标,front会随着数据输出而改变(变大),而rear则是随着数据输入而改变(变大)尾进头出,先进先出

 三、单链表链表(Linked List)

介绍:链表是有序的列表

1)链表是以节点的方式来存储

2)每个节点包括data域(数据域)和next域(指向下一个节点)

3)链表的各个节点不一定是连续的

4)链表分带头节点的链表和没有头结点的链表,根据实际的需求来确定

单链表存储结构示意图:(内存)

单链表(带头结点)逻辑结构示意图

单链表的常见面试题:

//node结点

public class HeroNode {
public int no;
public String name;
public HeroNode next; public HeroNode(int no, String name) {
this.no = no;
this.name = name;
} @Override
public String toString() {
return
"no=" + no +
", name=" + name ;
}
} //单链表相关函数 import jdk.nashorn.internal.objects.annotations.Where; import java.util.Stack; public class HeroLinkedList { private HeroNode head = new HeroNode(0,""); public HeroNode getHead() {
return head;
} //添加或者修改存在的节点
public void addOrUPdateNode(HeroNode node){
if (node == null) {
System.out.println("加入失败,不能加入空对象");
}
HeroNode temp = head;
while (true){
if (temp.next == null) {
temp.next = node;
break;
}
if (temp.next.no == node.no) {
temp.next.name = node.name;
break;
}
if ( temp.next.no > node.no && temp.no < node.no ) {
node.next = temp.next;
temp.next = node;
break;
}
temp = temp.next;
}
} //删除某个节点
public void deleteNode(int i){
HeroNode temp = head;
while (temp.next != null) {
if (temp.next.no == i) {
temp.next = temp.next.next;
return;
}
temp = temp.next;
}
System.out.println("删除失败,没有这个节点!");
} //展示所有的节点
public void allNode(){
HeroNode temp = head;
while (temp.next != null) {
System.out.println(temp.next);
temp = temp.next;
}
} //返回节点的所有个数
public int nodeSum(HeroNode head){
if (head == null || head.next == null) {
return 0;
}
int num = 0;
HeroNode temp = head;
while (temp.next != null) {
temp = temp.next;
num++;
}
return num;
} //查找单链表的倒数第N个节点
public void findHeroNode(HeroNode head,int n){
if (n <= 0 || n > nodeSum(head)) {
System.out.println("单链表中没有这个节点!");
return;
}
int m = nodeSum(head)-n;
HeroNode temp = head;
while (m>0){
temp = temp.next;
m--;
}
System.out.println(temp.next);
} //反转单向链表并输出
public void reverseHeroNode(){
//定义一个新的头结点
HeroNode reNode = new HeroNode(0,"");
boolean exange = false;
HeroNode tempHead = null;
if (head.next != null) {
tempHead = head.next;
}
HeroNode temp;
while (tempHead != null) {
temp = tempHead;
tempHead = tempHead.next;
temp.next = reNode.next;
reNode.next = temp;
exange = true;
}
if (exange){
head = reNode;
}
} //逆序打印单向链表
public void reversePrint(){
if (head == null) {
return;
}
//使用栈,先进后出的顺序,按正常顺序存入栈中,出栈时就是逆序
Stack<HeroNode> hero = new Stack<>();
HeroNode temp = head;
while (temp.next != null) {
hero.add(temp.next);
temp = temp.next;
}
while (!hero.isEmpty()) {
System.out.println(hero.pop());
} }
//合并两条单链表,使得排序之后仍然有序
public void mergesLinkedList(HeroLinkedList list){
if (list == null){
return;
}
if (list.head.next == null){
return;
}
HeroNode temp = list.head.next;
HeroNode tempAdd = null;
while (temp != null){
tempAdd = temp;
temp = temp.next;
this.addOrUPdateNode(tempAdd);
} } } //测试单链表相关方法
package com.zjl.linked_list; public class testLinkedList {
public static void main(String[] args) {
HeroNode node1 = new HeroNode(1, "张三");
HeroNode node5 = new HeroNode(5, "二麻子");
HeroNode node6 = new HeroNode(6, "王五");
HeroNode node2 = new HeroNode(2, "李四"); HeroNode node3 = new HeroNode(3, "大头");
HeroNode node4 = new HeroNode(4, "小鬼");
// HeroNode node31 = new HeroNode(3, "王五$$"); HeroLinkedList list = new HeroLinkedList();
HeroLinkedList list1 = new HeroLinkedList(); //添加节点
list.addOrUPdateNode(node1);
list.addOrUPdateNode(node2);
list.addOrUPdateNode(node5);
list.addOrUPdateNode(node6); list1.addOrUPdateNode(node3);
list1.addOrUPdateNode(node4);
//展示所有节点
list.allNode(); list1.allNode();
//删除某个节点
// list.deleteNode(3); // list.allNode(); //要删除的节点不存在时
// list.deleteNode(3);
// list.deleteNode(5); //获取节点的总个数
System.out.println(list.nodeSum(list.getHead()));
//找到单向链表的倒数第n个数
// list.findHeroNode(list.getHead(),1); //反转单链表
// list.reverseHeroNode();
// list.allNode(); //逆序输出单向链表
// list.reversePrint(); //合并两个单链表,并且合并之后依然有顺序
list.mergesLinkedList(list1);
list.allNode(); }
}

二、双向链表

特点:

1、具有next指向下一个指针,也有per指向上一个指针

2、查找方式,可以向前也可以向后

3、可以自我删除

单向链表和双向链表的不同:

//双向链表结点的定义

public class HeroNode {
public int no;
public String name;
public HeroNode next; public HeroNode per; public HeroNode(int no, String name) {
this.no = no;
this.name = name;
} @Override
public String toString() {
return
"no=" + no +
", name=" + name ;
}
}
//双向链表相关的方法
import com.zjl.linked_list.HeroNode;
import jdk.nashorn.internal.objects.annotations.Where; public class HeroDoubleLinkedList {
HeroNode head = new HeroNode(0, ""); //双向链表的添加和更改
public void addDoubleLinkedList(HeroNode node){
if (node == null){
return;
}
HeroNode temp = head;
while (true) {
if (temp.next == null){
temp.next = node;
node.per = temp;
break;
}
if (temp.next.no == node.no) {
temp.next.name=node.name;
break;
}
if ( temp.no < node.no && temp.next.no > node.no) {
node.next = temp.next;
temp.next.per = node;
temp.next = node;
node.per = temp;
break;
}
temp = temp.next;
}
}
//展示所有的双向链表
public void allDoubleLinkedList(){
if (head == null) {
return;
}
HeroNode temp = head;
while (temp.next != null) {
System.out.println(temp.next);
temp = temp.next;
}
} //删除双向链表的节点
public void deleteDoubleLinkedliseNode(int node){
if (head == null && node > 0) {
return;
}
boolean loop = true;
HeroNode temp = head;
while (temp != null) {
if (temp.no == node) {
temp.next.per = temp.per;
temp.per.next = temp.next;
loop = false;
break;
}
if (loop) {
temp = temp.next;
}
}
System.out.println("双向链表中,没有这个结点!"); } }
//测试双向链表;
import com.sun.org.apache.bcel.internal.generic.NEW;
import com.zjl.linked_list.HeroNode; public class testDoubleLinkedList {
public static void main(String[] args) {
HeroDoubleLinkedList list = new HeroDoubleLinkedList();
HeroNode node1 = new HeroNode(1, "张三");
HeroNode node2 = new HeroNode(2, "李四");
HeroNode node3 = new HeroNode(3, "二麻子");
HeroNode node4 = new HeroNode(4, "王五"); //添加结点到双向链表中
list.addDoubleLinkedList(node1);
list.addDoubleLinkedList(node2);
list.addDoubleLinkedList(node3);
list.addDoubleLinkedList(node4); //展示双向链表中的所有节点
list.allDoubleLinkedList(); //删除双向链表中的一个结点
list.deleteDoubleLinkedliseNode(2); list.allDoubleLinkedList();
}
}

三、单向环形链表

约瑟夫问题:

约瑟夫问题的解决思路,用一个头指针表示当前到达的位置,用一个辅助指针表示当前位置的前一个位置(方便进行删除操作),当first移动到要出圈的位置,就进行出圈操作,当已经到达first和辅助指针指向同一个位置时,就表示环形链表中自剩下一个结点,结束出圈

完成一个关于约瑟夫问题的求解:

//定义将用到的结点
package com.zjl.josepfu; public class Child {
public int no;
public Child next; public Child(int no) {
this.no = no;
} public int getNo() {
return no;
} @Override
public String toString() {
return "Child=" + no;
}
}
//定义在环形链表中,解决约瑟夫问题的方法
package com.zjl.josepfu; public class Josepfu {
public Child first = new Child(-1); //添加环形链表
public void addNewChild(int nums){
if (nums < 1) {
System.out.println("输入的数量不合适!");
}
Child temp = first;
Child boy = first;
if (nums == 1) {
boy.next = new Child(1);
boy = boy.next;
boy.next = temp.next;
}
else{
for (int i = 1; i <= nums; i++) {
boy.next = new Child(i);
boy = boy.next;
boy.next = temp.next;
}
}
} //输出环形链表中的所有结点
public void allJosepfu(){
if (first.next == null) {
System.out.println("该环没有结点");
return;
}
Child temp = first.next;
Child boy = first.next;
while (true) {
System.out.println(boy);
boy = boy.next;
if (boy == temp) {
break;
}
}
} //删除环中的某一个节点
public void deleteJosepfyNode(Child node){
if (node == null) {
System.out.println("删除的节点不能为空!");
}
if (first.next == null) {
System.out.println("该环形链表为空");
}
Child temp = first.next;
Child boy = first.next;
while (true) {
if (temp.no == node.no) {
first.next = temp.next;
}
if (boy.no == boy.next.no && boy.next.no == node.no) {
first.next = null;
break;
}
if (boy.next.no == node.no ) {
boy.next = boy.next.next;
break;
}
boy = boy.next;
}
} //获取环形链表的节点个数
public int allJosepfuNum(){
if (first.next == null) {
System.out.println("该环没有结点");
return 0;
}
int num = 0;
Child temp = first.next;
Child boy = first.next;
while (true) {
// System.out.println(boy);
boy = boy.next;
num++;
if (boy == temp) {
break;
}
}
return num;
}
//进行约瑟夫环的操作,根据输入的确定的起点和间隔,在已知的环形链表进行约瑟夫问题求解
public void testJosepfu(int k,int m){
if (k > allJosepfuNum() || k <= 0) {
System.out.println("该环中没有该起点!");
return;
}
Child boy = first;//找到头结点,开始一个环链表
//找到环形链表中的对应的起点k值
while (boy.next.no != k) {
boy = boy.next;
}
//循环的次数
int m_temp = m;
while (true) {
boy = boy.next;
m_temp--;
//每向下找一个结点就将间隔距离减一
//当距离变为0时找到对应的值输出,并从环链表中删除该值,并重新设置距离
if (m_temp == 0) {
System.out.println(boy);
deleteJosepfyNode(boy);
m_temp = m;
}
//当环形链表中只剩下一个结点的时候,就输出该结点并退出循环
if (allJosepfuNum() == 1) {
allJosepfu();
break;
}
} } //直接对约瑟夫问题进行求解,可以直接确定环的长度,起点,和间隔的距离
public void testJosepfu(int k, int m, int num) {
if (k < 1 || k > num) {
System.out.println("输入的参数有问题!");
}
addNewChild(num);
Child helper = first.next;
while (helper.next != first.next) {
helper = helper.next;
}
first = first.next;
while (first.no != k){
first = first.next;
helper = helper.next;
}
int temp = m-1;
while (true){
first = first.next;
helper = helper.next;
temp--;
if (helper == first){
allJosepfu();
break;
}
if (temp == 0) {
System.out.println(first);
first = first.next;
helper.next = first;
temp = m-1;
}
}
} }
//测试方法
package com.zjl.josepfu; public class TestJosepfu {
public static void main(String[] args) {
Josepfu josepfu = new Josepfu();
Josepfu josepfu1 = new Josepfu(); //给约瑟夫环加入结点
josepfu.addNewChild(5);
// System.out.println(josepfu.allJosepfuNum());
// //输出所有的结点
// josepfu.allJosepfu();
// josepfu.deleteJosepfyNode(new Child(3));
// josepfu.allJosepfu();
// System.out.println(josepfu.allJosepfuNum());
//测试进行约瑟夫实验
josepfu.testJosepfu(1,2);
// josepfu.allJosepfu(); //输入起点,间隔,以及环形链表的大小,进行约瑟夫问题的解决
josepfu1.testJosepfu(1,2,5); }
}

线性结构和非线性结构、稀疏数组、队列、链表(LinkedList)的更多相关文章

  1. Java数据结构介绍(线性结构和非线性结构)

    数据结构包括:线性结构和非线性结构. 线性结构 数据元素之间存在一对一的线性关系 包括顺序存储结构和链式存储结构.顺序存储的线性表称为顺序表,顺序表中的存储元素是连续的 链式存储的线性表称为链表,链表 ...

  2. 【Java数据结构学习笔记之一】线性表的存储结构及其代码实现

    应用程序后在那个的数据大致有四种基本的逻辑结构: 集合:数据元素之间只有"同属于一个集合"的关系 线性结构:数据元素之间存在一个对一个的关系 树形结构:数据元素之间存在一个对多个关 ...

  3. 【学习总结】java数据结构和算法-第三章-稀疏数组和队列

    相关链接 [学习总结]尚硅谷2019java数据结构和算法 github:javaDSA 目录 稀疏数组 队列 稀疏数组 稀疏数组介绍 图示 应用实例 代码实现 SparseArray.java:与二 ...

  4. 图解Java数据结构之稀疏数组

    在编程中,算法的重要性不言而喻,没有算法的程序是没有灵魂的.可见算法的重要性. 然而,在学习算法之前我们需要掌握数据结构,数据结构是算法的基础. 我在大学的时候,学校里的数据结构是用C语言教的,因为对 ...

  5. 【月光宝盒get√】用时间置换空间,聊聊稀疏数组的那些事儿

    背景 数据结构是指带有结构特性的数据元素的集合.在数据结构中,数据之间通过一定的组织结构关联在一起,便于计算机存储和使用.从大类划分,数据结构可以分为线性结构和非线性结构,适用于不同的应用场景. 线性 ...

  6. 线性表之顺序存储结构(C语言动态数组实现)

    线性表的定义:N个数据元素的有限序列 线性表从存储结构上分为:顺序存储结构(数组)和 链式存储结构(链表) 顺序存储结构:是用一段连续的内存空间存储表中的数据 L=(a1,a2,a3....an) 链 ...

  7. ※数据结构※→☆非线性结构(tree)☆============二叉树 顺序存储结构(tree binary sequence)(十九)

    二叉树 在计算机科学中,二叉树是每个结点最多有两个子树的有序树.通常子树的根被称作“左子树”(left subtree)和“右子树”(right subtree).二叉树常被用作二叉查找树和二叉堆或是 ...

  8. 2.2_线性表的顺序存储结构_参考集合ArrayList

    [线性表的顺序存储从结构] 指的是用一段连续的存储单元一次储存线性表的数据元素. [线性表的顺序存储的结构代码 C语言版] #define MAXSIZE 20 /*存储空间初始分配量*/ typed ...

  9. 线性表的顺序存储结构——java

    线性表的顺序存储结构:是指用一组地址连续的存储单元一次存放线性表的元素.为了使用顺序结构实现线性表,程序通常会采用数组来保存线性中的元素,是一种随机存储的数据结构,适合随机访问.java中ArrayL ...

随机推荐

  1. python 安装包时提示“unsupport command install”

    为什么提示找不到? 电脑安装了LoadRunnder,LoadRunner也有pip.exe,导致找不到python的exe 解决方法: 切换到python pip的路径进行安装,进到这个路径下,进行 ...

  2. CentOS 7 连接不到网络解决方法(设置静态ip)

    使用VM12创建虚拟机并安装CentOS 7,但是安装完成后发现连接不到网络. ping jd.com发现不通 因为在创建虚拟机的时候 我们选择的是NAT模式 这里给出NAT模式下对应的的解决方法: ...

  3. Python爬取中国知网文献、参考文献、引证文献

    前两天老师派了个活,让下载知网上根据高级搜索得到的来源文献的参考文献及引证文献数据,网上找了一些相关博客,感觉都不太合适,因此特此记录,希望对需要的人有帮助. 切入正题,先说这次需求,高级搜索,根据中 ...

  4. mysql-5.7.20-winx64安装图解教程

    原文链接:https://www.toutiao.com/i6494052843912167949/ 将安装包解压 解压目录 鼠标右键"我的电脑",弹出"快捷菜单&quo ...

  5. 贝塞尔曲线(面)二三维可视化(Three+d3)

    贝塞尔曲线(面)二三维可视化(Three+d3) 在学完 games101 几何后开始实践,可视化贝塞尔曲线 我想实现三维的贝塞尔曲线,用 threejs,但是 threejs 控制太麻烦了,因此,我 ...

  6. 【C】C语言大作业——学生学籍管理系统

    文章目录 学生管理系统 界面 主界面 登陆界面 注册界面 管理界面 学生界面 退出界面 链接 注意 学生管理系统 学C语言时写的一个大作业,弄了一个带图形界面的,使用的是VS配合EasyX图形库进行实 ...

  7. 【C语言】将文本中汉字读入字符数组输出乱码

    输出中文字符乱码 今天从文件中将中文读入字符数组后输出发现其中文变成了乱码,,令人头大. 解决办法 将文本编码格式改成ANSI即可. 打开记事本->文件->另存为->更改编码格式-& ...

  8. 你管这叫代理模式(Proxy Pattern)

    代理模式   代理模式即给一个真实类提供一个代理类,该代理类代替真实类完成其功能,一般还可在代理类上添加一些真实类不具有的附加功能,通俗来讲代理模式就是我们生活中常见的中介,代理模式又可分为静态代理和 ...

  9. Qt之锁

    mythread.h: #ifndef MYTHREAD_H #define MYTHREAD_H #include <QObject> #include<QMutex> cl ...

  10. gin中只绑定url查询字符串

    package main import ( "github.com/gin-gonic/gin" "log" ) type Person struct{ Nam ...