今天我们在Java的基础只是中穿插一点数据结构与算法的知识,学过计算机专业的同学抖音该知晓数据结构与算法的重要性。在这里我只总结一些较为常用的数据结构与算法,其余的可以找一些资料另做学习了解!
数据结构(data structure)是带有结构特性的数据元素的集合,它研究的是数据的逻辑结构和数据的物理结构以及它们之间的相互关系,并对这种结构定义相适应的运算,设计出相应的算法,并确保经过这些运算以后所得到的新结构仍保持原来的结构类型。简而言之,数据结构是相互之间存在一种或多种特定关系的数据元素的集合,即带“结构”的数据元素的集合。“结构”就是指数据元素之间存在的关系,分为逻辑结构和存储结构。
数据结构就是了解数据存储在内存中的顺序和位置关系;算法就是为求解一个问题锁需要遵循的、被清楚指定的简单指令的集合。数据结构是为算法服务的,算法是要作用在特定的数据结构上的。
常见的数据结构与算法:
数据结构:数组、链表、栈和队列、散列表 hash、二叉树、堆、跳表、图
算法:递归、排序、搜索、哈希、贪心、分治、回溯、动态规划、字符串匹配
递归:
程序调用自身的编程技巧称为递归( recursion)。递归作为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。
问题:假设有 n 级台阶,人可以每步跨 1 级或者 2 级台阶,上这 n 级台阶有多少种方法
public class 递归 {
public static int run(int n) {
if (n == 1) {
return 1;
}
if (n == 2) {
return 2;
}
return run(n - 1) + run(n - 2);
}
public static void main(String[] args) {
int res = run(10);
System.out.println(res);
}
}
问题:1.堆栈溢出。2.重复计算。
排序算法:
排序方法的衡量标准:时间复杂度、空间复杂度和稳定性
Java 中的排序算法:冒泡、插入、选择、快速、希尔、归并、堆
冒泡排序:
冒泡排序(Bubble Sort):它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。
冒泡排序算法的原理如下:
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
public class BubbleSort{
public static void main(String[] args) {
int[] arr = new int[] { 2, 3, 1, 7, 5 };
for (int i = 1; i < arr.length; i++) {
for (int j = 0; j < arr.length - i; j++) {
if (arr[j] > arr[j + 1]) {
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
快速排序:
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据比另一部分的所有数据要小,再按这种方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,使整个数据变成有序序列。
public class QuickSort{
public static void main(String[] args) {
int[] arr = new int[10];
Random r = new Random();
for (int i = 0; i < arr.length; i++)
arr[i] = r.nextInt(100);
quickSort(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(arr));
}
public static void quickSort(int[]arr,int start,int end){
if(start<end){
int p=arr[start];
int low =start;
int high=end;
while(low<high){
while(low<high && arr[high]>=p){
high--;
}
arr[low]=arr[high];
while(low<high && arr[low]<=p){
low++;
}
arr[high]=arr[low];
arr[low]=p;
quickSort(arr,start,low);
quickSort(arr,low+1,hend);
}
}
}
}
数据结构概论
线性表:
线性表是最基本、最简单、也是最常用的一种数据结构。线性表(linear list)是数据结构的一种,一个线性表是n个具有相同特性的数据元素的有限序列。
线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的(注意,这句话只适用大部分线性表,而不是全部。比如,循环链表逻辑层次上也是一种线性表(存储层次上属于链式存储,但是把最后一个数据元素的尾指针指向了首位结点)。
特征:
1.集合中必存在唯一的一个“第一元素”。
2.集合中必存在唯一的一个 “最后元素” 。
3.除最后一个元素之外,均有唯一的后继(后件)。
4.除第一个元素之外,均有唯一的前驱(前件)。
数组:
数组(Array)是有序的元素序列。若将有限个类型相同的变量的集合命名,那么这个名称为数组名。组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量。用于区分数组的各个元素的数字编号称为下标。数组是在程序设计中,为了处理方便, 把具有相同类型的若干元素按有序的形式组织起来的一种形式。这些有序排列的同类数据元素的集合称为数组。数组是用于储存多个相同类型数据的集合。
特点:
1.数组是相同数据类型的元素的集合。
2.数组中的各元素的存储是有先后顺序的,它们在内存中按照这个先后顺序连续存放在一起。
3.数组元素用整个数组的名字和它自己在数组中的顺序位置来表示。例如,a[0]表示名字为a的数组中的第一个元素,a[1]代表数组a的第二个元素,以此类推。
链表:
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。
数组需要一块连续的内存空间存储数据,对内存要求较高。链表通过指针可以将一组零散的内存块串联起来使用。 数组擅长按照下标进行随机访问,链表擅长删除、插入操作具体实现:在链表中使用节点存储数据,并使用引用串联各个元素。每个节点除了存储数据本身之外,还需要额外存储下一个节点的地址。
单向链表:
public class Node {
private int data;//存储具体数据
private Node next;//记录下一个节点的引用,尾节点指向 null
}
//创建 2 个节点的流程
Node node1=new Node();
node1.setData(123);//具体存储数据,next 此时为 null,所以 node1 是一个尾节点 Node
node2=new Node();
node2.setData(456);
node1.setNext(node2);//使 node1 的下一个元素指针指向到 node2 对象
public class LinkedList{
private Node head=null; //整个链表的头指针
public static class Node{
private int data;
private Node next;
}
}
新增数据:
public void insert(Node a,Node b){//在节点a后面插入新节点b
if(a==null){//在链表的头部插入添加数据b
b.next=head;
head=b;
}else{
b.next=a.next;
a.next=b;
}
}
删除数据:
//删除已知前驱节点为a的节点b,b的前驱节点为a
public void remove(Node a,Node b){
if(a==null){
head=head.next;
}else{
a.next=b.next;
}
查找节点:
public void find(int value){
Node p=head;
while(p!=null && p.data!=value){
p=p.next;
}
return p;
}
获取制定下标的节点:
public void get(int index){
Node p=head;
int res=0;
while(p!=null && res!=index){
res++;
p=p.next;
}
return p;
}
树
树实际上就是一种抽象数据类型 ADT 或者实现这种抽象数据类型的数据结构,可以用于模拟具有树状结构性质的数据集合,是由 n 个有限节点构成的一个具有层次关系的集合。
树结构特点:
1、每个节点都只有有限个子节点或者无子节点
2、没有父节点的节点称为根节点
3、每个非根节点尤其仅有一个父节点
4、除了根节点外,每个子节点可以分为多个互不相关的子树
5、树中没有环路 cycle
二叉树:二叉树就是每个节点最多有 2 个分叉子节点,具体的存储方式有基于指针的链式存储和基于数组的顺序存储,最常见的是基于指针的方式,基于数组的方式比较浪费内存。
二叉树的遍历方式有前序遍历、中序遍历和后序遍历三种方式
前序遍历:根--左--右
public void preOrder(Node root){
if(root==null)
return;
System.out.println(root.data);
preOrder(root.left);
preOrder(root.right);
}
中序遍历:左--根--右
public void middleOrder(Node root){
if(root==null)
return;
middleOrder(root.left);
System.out.println(root.data);
middleOrder(root.right);
}
后序遍历:左--右--根
public void postOrder(Node root){
if(root==null)
return;
postOrder(root.left);
postOrder(root.right);
System.out.println(root.data);
}
排序二叉树:首先如果二叉树满足条件每个节点:左子树的所有节点值都小于它的根节点,而且所有右子树节点值大于它的根节点,这样的二叉树就是排序二叉树
好了,今天的数据结构与算法的最常见的一些知识就先总结到这里吧,其他的我们如果有需要,可以再网上查找相关详细资料,然后慢慢了解学习!欢迎大家的指正!!!我们可以互相学习交流,十分感谢大家!下一篇文章我将会学习Java集合的相关知识,当然,也不能忘记之前所学习的相关知识点哦!