JAVA的线性表数据结构的超详解

目录

顺序表的顺序存储结构

1.数组

2.顺序表

顺序表的声明,存储操作以及效率分析

1.泛型类

2.顺序表的插入操作

3. 顺序表的删除操作 

 4.顺序表查询操作

5.顺序表的应用

线性表的链式存储结构 

单链表的基本操作


 

顺序表的顺序存储结构

数组是实现顺序存储结构的基础

1.数组

程序设计语言中,数组(Array)具有相同数据类型,是一个构造数据类型。

一维数组占用一块内存空间,每个存储单元的地址是连续的,数据的存储单位个数称为数组容量。设数组变量为a,第i个元素(存储单元)为a[i],其中序号i称为下标,一维数组使用一个下标唯一确定一个元素。

如果数据存储结构存取任何一个元素的时间复杂度是O(1),则称其为随机存储结构。因此,数组是随机存储结构。

数组一旦占用一片存储空间,其地址和容量就是确定的,不能更改。因此,数组只能进行赋值,取值两种操作,不能进行插入和删除操作。当数组容量不够时,不能就地扩容。

72b70cee8842407bb7ab67afac259251.png

2.顺序表

线性表的顺序存储结构称为顺序表,它使用一维数组一次存放线性表的数据,且顺序表的性质和数组是一样的,因为顺序表的底层就是用数组来实现的。

顺序表的表现特点:

  1. 随机访问,可以在O(1)时间内找到第i个元素
  2. 存储密度高,每个节点只存储数据元素
  3. 扩展容量不方便(即便采用动态分配的方式实现,扩展长度的时间复杂度也比较高)
  4. 插入和删除操作不方便,需要移动大量元素

顺序表的声明,存储操作以及效率分析

1.泛型类

声明SeqList<T>为泛型类,类型形式参数称为泛型,T表示顺序表数据元素的数据类型。

JAVA语言约定。泛型<T>的实际参数必须是类,不能是int,char等基本数据类型。如果需要表示基本数据类型,也必须采用基本数据类型的包装类,如Integer,Character等等。

2.顺序表的插入操作

de0d322dc6b44978aae8ec691d79adac.png

public class SequentialList{private int[] array;//用于顺序表的数组private int size;//顺序表的实际长度public SequentialList(int capacity){array =new int[capacity];size=0;}//插入操作public boolean insert(int index,int element){//检查索引是否合法if (index<0||index>size){System.out.println("插入的位置不合法");return false;}//如果数组已满,则无法插入if (size==array.length){System.out.println("顺序表已满,无法插入");return false;}//从插入位置开始,所有的元素向后移动一位for (int i =size;i>index;i--){array[i]=array[i-1];}//插入元素array[index]=element;//更新顺序表的长度size++;return true;}public void printList(){for (int i = 0; i < size; i++) {System.out.println(array[i]+" ");}System.out.println();}public static void main(String[] args) {SequentialList list =new SequentialList(10);list.insert(0, 3); // 在索引0处插入元素3list.insert(1, 7); // 在索引1处插入元素7list.insert(2, 1); // 在索引2处插入元素1list.insert(3, 4); // 在索引3处插入元素4list.printList(); // 打印顺序表}}

3. 顺序表的删除操作 

ce89004d93a2406a8c92cf2ff9b963a8.png 对顺序表进行插入和删除操作时,算法所花费的时间主要用于移动元素。若插入或删除在最前面,则需要移动n个元素;若插入或删除元素在最后,则移动元素为0。设插入x作为第i个元素的概率为p,插入一个元素的平均移动到次数为O(n)。

 4.顺序表查询操作

根据查找条件,对顺序表进行查找操作,采用顺序查找算法,在查找过程中,需要将key与顺序表顺序表元素逐个比较是否相等。而比较对象对象相等规则有原数所属的T类的equals(Object)方法实现。

   public int search(T key){for(int i =0;i<this.n;i++){if (key.equals(this.element[i])){return i;}}return -1;}

顺序查找的比较次数取决于元素位置。时间复杂度也为O(n)。

静态顺序表的特性:

1. 固定大小:静态顺序表在创建时分配固定数量的内存空间,这个大小在定义后不能改变。

2. 内存分配:内存在编译时分配,因此内存使用是静态的,不会随程序运行而改变。

3. 空间浪费:如果实际存储的元素少于分配的空间,会造成内存浪费。

4. 无需移动元素:插入和删除操作不需要移动大量元素,因为有足够的空间来容纳新元素或释放空间。

5. 简单实现:由于内存空间固定,实现起来相对简单。

 顺序表利用元素的物理存储次序反映线性表元素的逻辑次序,不需要额外空间来表达元素之间的关系。

插入和删除操作效率都很低。每插入或删除一个元素,元素移动量大,平均移动顺序表一半的元素。

顺序表(也称为数组)支持通过索引直接访问元素,这种情况下查找的时间复杂度是 O(1)。这意味着无论数组有多大,访问任何元素的时间都是恒定的,因为数组元素在内存中是连续存储的,可以通过简单的地址计算直接定位到元素。

如果你不知道元素的索引,而需要通过元素的值来查找它的位置,那么通常需要进行线性查找,这两种情况的时间复杂度为 O(n) 。

5.顺序表的应用

求解Josephus环的问题。

 

Josephus问题是一个著名的数学问题,以公元1世纪的犹太历史学家约瑟夫斯(Flavius Josephus)的名字命名。据说,在罗马占领期间,约瑟夫斯和他的39个同胞犹太士兵被罗马军队包围在一座山洞中,他们决定宁死不屈,并通过抽签决定自杀的顺序,每杀一个人,就按事先规定的顺序数到下一人,直到所有人都死去。约瑟夫斯和另外一个人是最后两个幸存者,他们决定不自杀,而是向罗马军队投降。

这个问题可以形式化为:n个人围成一圈,从第一个人开始,每数到第m个人,就将其处决,然后从下一个人重新开始数。这个过程一直进行,直到所有人都被处决。问题是,给定n和m,如何找到最后被处决的人的初始位置?

 ee6395601e1d495986b87514536e9e11.jpeg

 

import java.util.ArrayList;public class Josephus {//n个人,n>0;从start开始技术,0<=start<n,每次数到distance的人出环,0<distance<npublic Josephus(int n ,int start,int distance){if (n<=0||start<0||start>=n||distance<=0||distance>=n)throw new IllegalArgumentException("n="+n+",start="+start+",distance="+distance+"");//创建顺序表实例,元素类型是字符串,构造方法参数指定顺序表容量,省略时取默认值ArrayList<String> list =new ArrayList<>();for (int i =0;i<n;i++){list.add((char)('A'+i)+"");}System.out.println(list.toString());while(n>1){//循环,每次计算删除一个元素start =(start+distance-1)%n;//输出删除的start位置对象和顺序表中的剩余元素,两者均为O(n)System.out.println("删除"+list.remove(start).toString()+","+list.toString());n--;}System.out.println("被赦免的人是"+list.get(0));}public static void main(String[] args) {new Josephus(5,1,3);}
}

运行结果: 

[A, B, C, D, E]
删除D,[A, B, C, E]
删除B,[A, C, E]
删除A,[C, E]
删除C,[E]
E

线性表的链式存储结构 

线性表采用的是链式存储结构,别名单链表,用于储存逻辑关系为“一对一”的数据。与顺序表不同,链表不限制数据的物理存储状态,换句话说,使用链表存储的数据结构,其物理存储位置是随机的,因此必须采用指针变量记载前驱或后续元素的存储地址,存储数据元素之间的线性关系。

 物理存储结构:在物理层面上,单链表的节点不需要在内存中连续存储。每个节点可以独立地存储在内存的任何位置,通过指针指向下一个节点,从而在逻辑上形成一个线性序列。这意味着,尽管节点在内存中是分散的,但它们通过指针连接起来,形成了一个完整的链表。

例如:

3572e8178ffe46ba9cced64943af6933.jpeg

 

存储一个数据元素的存储单元称为节点(node)。结点结构如下,至少包含两个部分。

结点(数据域,地址域)   //数据域存储数据元素,地址域(也称为链)存储前驱或后续元素地址

每个结点只有一个地址域的线性链表称为单链表,空链表的头指针head为null;一个单链表最后一个节点的地址域为null

一个完整的链表需要由以下几个部分组成:

1.头指针:一个普通的指针,它的特点是永远指向链表第一个结点的位置。很明显,头指针用于指明链表的位置,便于后期找到链表并使用表中的数据。

2.节点:链表中的节点细分为头节点,首元节和其他节点

A.头节点:其实就是一个不存任何数据的空节点,通常作为链表的第一个节点,对于链表来说,头节点不是必须的,它的作用只是方便解决某些实际问题

B.首元节点:只是堆链表的第一个存有数据节点的一个称谓,没有实际含义。

C.其他节点:链表中其他的节点

 

ad1032833cef4c33a26351f692f777cf.jpeg

单链表的基本操作

1.单链表的插入操作

在单链表中插入一个节点,根据不同的插入位置,分一下几种情况

  1. 在头节点前插入
  2. 在尾部插入
  3. 在某个特定的位置插入

0fb18b9dcf3d45c9b13126313e9c95dd.png

过程分析:

单链表第 i 个数据插入结点的算法思路:

    1)声明一指针 p 指向链表头结点,初始化 j 从1开始

    2)当 j<i 时,就遍历链表,让 p 的指针向后移动,不断指向下一结点,j 累加 1

    3)若到链表末尾为空,则说明第 i 个结点不存在

    4)否则查找成功,在系统中生成一个空节点s

    5)将数据元素 e 赋值给 s->data

    6)单链表的插入标准语句 s->next=p->next; p->next=s;

    7)返回成功

public class test3  {private Node head;//头节点//节点内部类private class Node{int data;Node next;Node(int data){this.data =data;this.next=null;}}//在链表的头部插入新的节点public void insertAtHead(int data){Node newNode =new Node(data);//创建一个新的节点newNodenewNode.next=head;//建立的新的节点Node指向head节点的链,即插入newNode节点在head节点的前head=newNode;//使head指向newNode节点,则p节点成为第0个节点}//到链表的尾部插入新的节点public void insertAtTail(int data){Node newNode=new Node(data);//创建一个新的节点if(head==null){//检查头节点是否为空head=newNode;//如果链表为空,这行代码讲新节点赋值给头节点head}else{Node current =head;//这个用来辅助遍历链表while(current.next!=null){//直到current指向链表的最后一个节点current=current.next;//不断指向链表中下一个节点}current.next=newNode;//当循环结束时,newNode连接到链表的结尾}}//在指定的位置插入新的节点public void insertAtPosition(int position,int data){if (position==0){insertAtHead(data);return;}Node newNode =new Node(data);Node current=head;for (int i =0;i<position-1&&current!=null;i++){current=current.next;}if (current==null){//如果current为null,说明指定的插入位置超出了链表当前长度System.out.println("position"+position+"is out of bounds");return;}newNode.next =current.next;current.next=newNode;}}

疑问:为什么在单链表数据读取的时候,声明的指针p指向链表的第一个节点,而在单链表插入的时候,声明的指针p指向链表第一个节点,而在单链表插入时候,声明的指针p指向链表的头节点。

分析:

  1. 单链表读取的时候,是从头开始查找的,如果找到直接读取数据返回,显然这个跟头节点没什么关系,直接从第一个节点开始即可。
  2. 单链表插入的时候,查找到节点的情况下,是需要将p的后续节点改成s的后续节点,再将节点s变成p的后续节点。声明p指针指向链表头节点,p的后续节点就是第一节点,p的后续节点就是第一节点,就相当于从第一节点前插入,这显然符合要求。
  3. 如果声明的指针p指向第一个节点,那通过这个插入语句后,就相当于插入了第二个节点前,显然不符合要求。

2.删除单链表

删除单链表中的指定节点,通过改变节点的next域,就可以改变节点之间的连接关系,不需要移动元素。

89c0ca4eb2f845da8cd3a77dff9453e5.png

5a3ee0c139f84fc681a508b117e539ce.png

删除节点的算法思路:

    1)声明一指针 p 指向链表头结点,初始化 j 从1开始

    2)当 j < i 时,就遍历链表,让 p 的指针向后移动,不断指向下一个结点,j 累加1

    3)若到链表末尾 p 为空,则说明第 i 个结点不存在

    4)否则查找成功,将欲删除的结点  p->next 赋值给 q

    5) 单链表的删除标准语句 p->next = q->next

    6) 将 q 结点中的数据赋值给 e, 作为返回

    7) 释放 q 结点

    8) 返回成功

    // 删除特定值的节点public void delete(int val) {if (head == null) {return;}if (head.val == val) {head = head.next;} else {ListNode curr = head;while (curr.next != null && curr.next.val != val) {curr = curr.next;}if (curr.next != null) {如果循环结束后,curr.next 不为 null,
说明找到了一个值等于 val 的节点。
这时,将 curr.next 更新为 curr.next.next
这样就将值等于 val 的节点从链表中删除了。curr.next = curr.next.next;}}}

3.查找倒数第k个元素

class LinkedList{ListNode head;//链表的头节点//查找倒数第k个元素public ListNode findKthFromEndUsingTwoPasses(ListNode head,int k ){//第一次遍历,计算链表的长度int length =0;ListNode current =head;while(current!=null){length++;current=current.next;}//如果k大于链表长度,则不存在倒数第k个元素if (k>length){throw new IllegalArgumentException("k的值大于链表长度");}//第二次遍历,找到第length-k个节点int index =0;current =head;while(current!=null&&index<length-k){current=current.next;index++;}return current;//返回倒数第j个节点}//打印链表节点的值public void printList(ListNode head){ListNode current =head;while(current!=null){System.out.print(current.val+"->");current=current.next;}System.out.println("null");}public static void main(String[] args) {LinkedList linkedList = new LinkedList();linkedList.head = new ListNode(1);linkedList.head.next = new ListNode(2);linkedList.head.next.next = new ListNode(3);linkedList.head.next.next.next = new ListNode(4);linkedList.head.next.next.next.next = new ListNode(5);System.out.println("Original List:");linkedList.printList(linkedList.head);int k = 2; // 假设我们要找倒数第2个元素ListNode kthNode = linkedList.findKthFromEndUsingTwoPasses(linkedList.head, k);if (kthNode != null) {System.out.println("The " + k + "th node from the end has value: " + kthNode.val);} else {System.out.println("The " + k + "th node from the end does not exist.");}}
}

4.单链表反转

思路分析:

对于这个问题,我们选择迭代的方法,因为他不需要额外的存储空间,并且时间复杂度为O(n),其中n是链表的长度。

我们使用三个指针,prev初始化为null,以为你它将指向新链表的最后一个节点。即原链表的第一个节点,用于遍历链表,next用于临时存储current的下一个节点。

  1. 首先我们将current.next保存到next,因为下一步我们需要移动current
  2. 然后,将current.next指向prev,这是反转链表的关键,它改变了节点的指向,使其指向前一个节点而不是后一个节点。
  3. 接着,将prev和current向前移动一位,prev变为当前的current,current变为next。 

class LinkedList{ListNode head;//链表的头节点//反转单链表public void reverse(){ListNode prev =null;//初始化prev为null,它将指向反转后的前一个节点ListNode current= head;//用于遍历当前节点ListNode next =null;//用于存储下一个节点while (current!=null){next=current.next;//在改变current的next之前,先保存下一个节点current.next=prev;//反转current节点的next指向prev,这是反转的关键步骤prev=current;  //将prev前移一位,现在prev指向currentcurrent=next;//将current前移一位,现在都current指向next}head=prev;//完成反转后,prev指向原链表的最后一个节点,即新链表的头节点}//打印链表public void printList(){ListNode current =head;//头节点开始遍历while(current!=null){System.out.println(current.val+"->");current=current.next;}System.out.println("null");}
}

总结:

1.单链表不是随机存储结构

虽然访问单链表第0个节点的时间是O(1);但是要访问第i个节点,必须从head开始沿着链的方向查找,遍历部分单链表,进行i次都p=p.next操作,时间复杂度为O(n),所以单链表不是随机存储,

从整个算法来说,我们很容易推导出:它们的时间复杂度都是O(n)。如果在我们不知道第i个节点的指针位置 ,单链表数据结构在插入和删除操作上,与线性表的存储结构是没有太大优势的。但如果,我们希望从i个位置,插入10个节点,对于存储结构,意味着,每一次插入都需要移动n-i个节点。每次都是O(n),而单链表,我们只需要在第一次时,找到第i个位置的指针,此时为O(n),接下来只是简单得通过赋值移动指针,时间复杂度都是O(1)。对于插入和删除数据越频繁的操作,单链表的优势越明显。

插入或者删除后驱节点的时间是O(1),但是前驱节点或者删除自己的时间是O(n)

07a6c419813e4115a3ce4529afb1973c.jpeg

如果front指向单链表中的一个节点,那么插入或者删除后续节点的时间为O(1)。

如果p指向单链表的一个节点,要在p节点前插入一个节点或者删除p节点自己,必须修改p的前驱节点的next域。因此需要再次遍历单链表,找到p前驱节点front,转换为插入或者删除front的后续节点。

下面来做一道题来锻炼一下吧:

题目是使用单链表实现素数线性表

public class PrimeLinkedList {ListNode head;public boolean isPrime(int num){if (num<1){return false;}for (int i =2;i*i<=num;i++){if (num%i==0){return false;}}return true;}public void insertPrime(int num){if (!isPrime(num)){System.out.println(num+"不是素数");return;}ListNode newNode =new ListNode(num);if (head==null){head=newNode;}else{ListNode current=head;current =head;while(current.next!=null){current=current.next;}//这段代码遍历链表到最后一个节点,然后将新的节点连接到链表的末尾current.next=newNode;}}public void printList() {ListNode current = head;while (current != null) {System.out.print(current.val + " ");current = current.next;}System.out.println();}
}class Main {public static void main(String[] args) {PrimeLinkedList primeList = new PrimeLinkedList();// 假设我们想插入以下数字int[] numbers = {2, 3, 4, 5, 6, 7, 11, 13, 17, 19, 23};for (int number : numbers) {primeList.insertPrime(number);}primeList.printList();}
}

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/41692.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

随手记录: Ubuntu NVIDIA显卡驱动安装后 屏幕亮度无法调节 无法连接外显示器等问题

背景 一句话&#xff1a;简单记录帮身边人装系统发现 GPU和外接显示器的无法连接&#xff0c;同时亮度无法调节等新问题 设备型号&#xff1a; 联想笔记本&#xff1a;ThinkBook 16p Gen2CPU&#xff1a;AMD Ryzen 7 5800HGPU&#xff1a;RTX 3060 问题描述及流程&#xff…

类继承-多继承虚继承

#include<iostream> using namespace std; class A1 { public:int a 10;}; class A2 { public:int b 20; }; class B :public A1, public A2 { public:int c 30; }; int main(){B b;cout << b.a << b.b << b.c << endl;return 0; } 如果基类…

STM32-HAL-SDIO-(sd卡的识别,整理后的版本)

1STM32Cube操作 1-1配置时钟 1-2配置调试端口 1-3配置uart 1-4配置SDIO 选择数据传输引脚个数 需改配置&#xff08;图中改了两处&#xff0c;选中的和最后一个&#xff09; 1-5打开DMA 传输方向改为图中的&#xff08;由内转向外设&#xff09;在改图中的一次读写的大小 1-…

图像处理调试软件推荐

对于图像处理的调试&#xff0c;使用具有图形用户界面&#xff08;GUI&#xff09;且支持实时调整和预览的图像处理软件&#xff0c;可以大大提高工作效率。以下是几款常用且功能强大的图像处理调试软件推荐&#xff1a; ImageJ/FijiMATLABOpenCV with GUI LibrariesNI Vision …

Java中关于构造代码块和静态代码块的解析

构造代码块 特点&#xff1a;优先于构造方法执行,每new一次,就会执行一次 public class Person {public Person(){System.out.println("我是无参构造方法");}{System.out.println("我是构造代码块"); //构造代码块} }public class Test {public stati…

【推荐图书】深入浅出Spring Boot 3.x

推荐原因 这部SpringBoot3.x经典之作&#xff0c;时隔六年迎来重磅升级&#xff01; 适合java开发相关读者 购买链接 商品链接&#xff1a;https://item.jd.com/14600442.html 介绍 书名&#xff1a;深入浅出Spring Boot 3.x ISBN&#xff1a;978-7-115-63282-1/ 作者&…

「ETL趋势」分区支持PostgreSQL、Greenplum、Gauss200, 定时任务支持Kettle

FineDataLink作为一款市场上的顶尖ETL工具&#xff0c;集实时数据同步、ELT/ETL数据处理、数据服务和系统管理于一体的数据集成工具&#xff0c;进行了新的维护迭代。本文把FDL4.1.9最新功能作了介绍&#xff0c;方便大家对比&#xff1a;&#xff08;产品更新详情&#xff1a;…

【国产开源可视化引擎Meta2d.js】钢笔

钢笔 钢笔是和其他众多绘图工具&#xff08;Photoshop、Sketch、Illustrator&#xff09;中一致的钢笔工具&#xff0c;能够很方便的在线绘制各种小图标 在线体验&#xff1a; 乐吾乐2D可视化 示例&#xff1a; // 开始绘画&#xff1a;curve。除了curve&#xff0c;还有poly…

上位机图像处理和嵌入式模块部署(mcu项目1:用户手册)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 一个完整的产品&#xff0c;除了上位机软件、固件、硬件、包装之外&#xff0c;一般还需要一个用户手册。好的用户手册应该能够兼顾到大多数人的认…

力扣(3200)- 三角形的最大高度

好方法&#xff1a; 垃圾方法&#xff1a;

吉洪诺夫正则化随笔

前言 前几天在回顾压缩感知中的特征选择与LASSO回归发现了这个Tikhonov regularization&#xff0c;查了一下叫个如题的名字。先来浅说一下正则化这玩意&#xff1a;正则化&#xff08;Regularization&#xff09;是一种用来防止模型过拟合&#xff08;Overfitting&#xff09…

孙溟㠭篆刻《睡片原谅一切,醒来不问过往》

孙溟㠭篆刻《睡片原谅一切&#xff0c;醒来不问过往》 佛陀言&#xff1a;睡前原谅一切&#xff0c;醒来不问过往&#xff0c;珍惜所有不期而遇&#xff0c;看淡所有不辞而别甲辰夏溟㠭于寒舍小窗下刊。

相关向量机RVM算法介绍继承sklearn-SVM-API实现回归预测算例

一、相关向量机RVM与支持向量机SVM对比 1、相关向量机&#xff08;RVM&#xff09; ①定义与原理 相关向量机&#xff08;Relevance Vector Machine, RVM&#xff09;是一种基于概率模型的机器学习算法&#xff0c;主要用于分类和回归分析。基于稀疏贝叶斯学习框架&#xff…

Springboot助农农产品销售系统-计算机毕业设计源码16718

摘要 SpringBoot助农农产品销售系统旨在通过利用SpringBoot框架开发一个便捷高效的农产品销售平台。该系统包括用户注册登录、商品浏览、购物车管理、订单生成、支付功能等模块。通过整合支付接口、地图定位、推荐系统等技术&#xff0c;提供给用户更好的购物体验。本文介绍了…

Docker安装遇到问题:curl: (7) Failed to connect to download.docker.com port 443: 拒绝连接

问题描述 首先&#xff0c;完全按照Docker官方文档进行安装&#xff1a; Install Docker Engine on Ubuntu | Docker Docs 在第1步&#xff1a;Set up Dockers apt repository&#xff0c;执行如下指令&#xff1a; sudo curl -fsSL https://download.docker.com/linux/ubu…

人工智能开发中的数据隐私

人工智能开发中的数据隐私对于建立用户信任和遵守严格法规至关重要。保护敏感信息可确保合乎道德的人工智能使用并防止有害的数据泄露。 为什么在人工智能开发中优先考虑数据隐私至关重要 人工智能的迅猛发展开启了一个前所未有的技术进步时代&#xff0c;彻底改变了各行各业&…

使用Python绘制双向条形图

使用Python绘制双向条形图 双向条形图效果代码 双向条形图 双向条形图用于比较两个类别的数值分布&#xff0c;条形在中轴线两侧对称排列。这种图表常用于显示两个变量的对比情况&#xff0c;例如男女不同年龄段人口数量对比。 效果 代码 import matplotlib.pyplot as plt i…

Shopee(虾皮)怎么获取流量?

店铺流量的高低会直接关联到卖家店铺单量&#xff0c;也关系到一个店铺的营业情况和利润&#xff0c;那么Shopee的流量从哪里来呢&#xff1f; Shopee的平台流量可分为五个部分&#xff1a; 1.自然流量 2.关键字广告流量 3.平台活动流量 4.营销流量 5.粉丝流量 怎么提升…

【C语言小知识】getchar与putchar

getchar与putchar getchar介绍putchar介绍总结 在学习c语言阶段存在着许多要求输入数值的例子&#xff0c;在输入字符时&#xff0c;如果使用scanf()和printf()根据%c转换说明读写字符&#xff0c;接下来介绍一堆字符输入/输出函数&#xff1a;getchar()和putchar()。 getchar…

Andriod安装termux并换源

问题汇总 Error: The repository ‘https://mirrors.tuna.tsinghua.edu.cn/termux/termux-package-24 stable Release’ does not have a Release file. 更换源&#xff08;这里使用的是清华大学源&#xff09; 打开文件 nano $PREFIX/etc/apt/sources.list手动修改 deb htt…