线性结构和非线性结构、稀疏数组、队列、链表(LinkedList)
一、线性结构和非线性结构
线性结构:
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)的更多相关文章
- Java数据结构介绍(线性结构和非线性结构)
数据结构包括:线性结构和非线性结构. 线性结构 数据元素之间存在一对一的线性关系 包括顺序存储结构和链式存储结构.顺序存储的线性表称为顺序表,顺序表中的存储元素是连续的 链式存储的线性表称为链表,链表 ...
- 【Java数据结构学习笔记之一】线性表的存储结构及其代码实现
应用程序后在那个的数据大致有四种基本的逻辑结构: 集合:数据元素之间只有"同属于一个集合"的关系 线性结构:数据元素之间存在一个对一个的关系 树形结构:数据元素之间存在一个对多个关 ...
- 【学习总结】java数据结构和算法-第三章-稀疏数组和队列
相关链接 [学习总结]尚硅谷2019java数据结构和算法 github:javaDSA 目录 稀疏数组 队列 稀疏数组 稀疏数组介绍 图示 应用实例 代码实现 SparseArray.java:与二 ...
- 图解Java数据结构之稀疏数组
在编程中,算法的重要性不言而喻,没有算法的程序是没有灵魂的.可见算法的重要性. 然而,在学习算法之前我们需要掌握数据结构,数据结构是算法的基础. 我在大学的时候,学校里的数据结构是用C语言教的,因为对 ...
- 【月光宝盒get√】用时间置换空间,聊聊稀疏数组的那些事儿
背景 数据结构是指带有结构特性的数据元素的集合.在数据结构中,数据之间通过一定的组织结构关联在一起,便于计算机存储和使用.从大类划分,数据结构可以分为线性结构和非线性结构,适用于不同的应用场景. 线性 ...
- 线性表之顺序存储结构(C语言动态数组实现)
线性表的定义:N个数据元素的有限序列 线性表从存储结构上分为:顺序存储结构(数组)和 链式存储结构(链表) 顺序存储结构:是用一段连续的内存空间存储表中的数据 L=(a1,a2,a3....an) 链 ...
- ※数据结构※→☆非线性结构(tree)☆============二叉树 顺序存储结构(tree binary sequence)(十九)
二叉树 在计算机科学中,二叉树是每个结点最多有两个子树的有序树.通常子树的根被称作“左子树”(left subtree)和“右子树”(right subtree).二叉树常被用作二叉查找树和二叉堆或是 ...
- 2.2_线性表的顺序存储结构_参考集合ArrayList
[线性表的顺序存储从结构] 指的是用一段连续的存储单元一次储存线性表的数据元素. [线性表的顺序存储的结构代码 C语言版] #define MAXSIZE 20 /*存储空间初始分配量*/ typed ...
- 线性表的顺序存储结构——java
线性表的顺序存储结构:是指用一组地址连续的存储单元一次存放线性表的元素.为了使用顺序结构实现线性表,程序通常会采用数组来保存线性中的元素,是一种随机存储的数据结构,适合随机访问.java中ArrayL ...
随机推荐
- ApkToolBoxGUI 0.0.8发布了!!
https://github.com/jiangxincode/ApkToolBoxGUI APKToolBoxGUI是一个程序员常用的小工具合集,有个比较友好的交互界面.主要包含编码转换,时间戳转换 ...
- 初识python: 小练习 之 笔记本电脑开机指定时间之后自动拍照并发送邮件
需求: 1.调用笔记本的摄像头,拍摄笔记本面前的照片:2.将照片发送给指定邮箱:3.发送邮件,提醒我们电脑已经开机,并附上笔记本拍摄的照片. 面向过程: #!/user/bin env python ...
- Flask_Flask-Mail邮件扩展(十三)
在开发过程中,很多应用程序都需要通过邮件提醒用户,Flask的扩展包Flask-Mail通过包装了Python内置的smtplib包,可以用在Flask程序中发送邮件. Flask-Mail连接到简单 ...
- ubuntu18.04 安装谷歌chrome浏览器
将下载源添加到系统源列表 # sudo wget http://www.linuxidc.com/files/repo/google-chrome.list -P /etc/apt/source.li ...
- react中使用styled-component
styled-component的使用地址(https://www.cnblogs.com/aichenxy/p/8672752.html)
- Leetcode系列之两数之和
Leetcode系列之两数之和 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标.你可以假设每种输入只会对应一个答案.但是,你 ...
- Word2010制作个人名片
原文链接: https://www.toutiao.com/i6488858441698771470/ 页面设置: 选择"页面布局"选项卡,"页面设置"功能组, ...
- Web发送邮件
1.首先注册一个163邮箱 自己的邮箱地址是xyqq769552629@163.com 登陆的密码是自己设定 使用邮箱发邮件,邮件必须开启pop和smtp服务,登陆邮件 开启SMTP服务,这个时候提示 ...
- 基于Appium的APP自动化测试基础--美团APP的实例
转:https://blog.csdn.net/Tigerdong1/article/details/80159156 前段时间用一种流行语言,一个主流工具,一个实用框架,写了一个美团app自动化测试 ...
- 【刷题-LeetCode】151 Reverse Words in a String
Reverse Words in a String Given an input string, reverse the string word by word. Example 1: Input: ...