数据结构顺序表和链表(超详细)

news2024/11/26 3:51:09

 线性表:

线性表 linear list n 个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使
用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串 ...
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,
线性表在物理上存储时,通常以数组和链式结构的形式存储。

顺序表

概念及结构

  顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存
储。在数组上完成数据的增删查改。
顺序表一般可以为: 

静态顺序表:使用定长数组存储元素。

 动态顺序表:使用动态开辟的数组存储。

 如果将一开始动态开辟的内存填满,则会进行扩容,

扩容分两种情况:

原地扩容:在已开辟的动态内存后进行判断,如果后方内存大小足够扩容到新定义的大小,则在之前开辟的内存后面加上一段,以达到新定义内存大小;

异地扩容:如果在已开辟的动态内存后进行判断,后方的大小不足以扩容到新定义的大小,则会在内存中寻找一块新的足够容纳新定义大小的空间,并将之前的数据拷贝到新空间,再释放之前定义的动态内存空间;

接口实现

静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空
间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间
大小,所以下面我们实现动态顺序表。

typedef int SLDateType;

typedef struct SeqList
{
    SLDateType* a;//动态开辟的数组
    int size;    //数据个数
    int capacity;//容量空间大小
}SL;


//初始化
void SLInit(SL* ps);

//释放或销毁
void SLDestroy(SL* ps);

//显示或打印
void SLPrintf(SL* ps);

//尾插
void SLPushBack(SL* ps, SLDateType x);
//尾删
void SLPopBack(SL* ps);
//头插
void SLPushFront(SL* ps, SLDateType x);
//头删
void SLPopFront(SL* ps);

//扩容
void SLCheckDestroy(SL* ps);

//顺序表查找
int SLFind(SL* ps,int n);

// 顺序表在pos位置插入x
void SLInsert(SL* ps, int pos, SLDateType x);

// 顺序表删除pos位置的值
void SLErase(SL* ps, int pos);

//顺序表修改
void SLModify(SL* ps,int pos,SLDateType x);

#define _CRT_SECURE_NO_WARNINGS 1

#include "Sequence.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>


//初始化
void SLInit(SL* ps)
{
    ps->a = (SLDateType*)malloc(sizeof(SLDateType*)*4);
    if (ps->a == NULL)
    {
        perror("malloc failed");
        exit(-1);
    }
    ps->size = 0;
    ps->capacity = 4;
}


//释放或销毁
void SLDestroy(SL* ps)
{
    free(ps->a);
    ps->a = NULL;
    ps->capacity = ps->size = 0;
}


//显示或打印
void SLPrintf(SL* ps)
{
    int i = 0;
    for (i = 0; i < ps->size; i++)
    {
        printf("%d ", ps->a[i]);
    }
    printf("\n");
}

//扩容
void SLCheckDestroy(SL* ps)
{
    if (ps->size == ps->capacity)
    {
        SLDateType* tmp = (SLDateType*)realloc(ps->a, sizeof(SLDateType) * 2 * ps->capacity);
        if (tmp == NULL)
        {
            perror("realloc failed");
            exit(-1);
        }
        ps->a = tmp;
        ps->capacity *= 2;
    }
}


//尾插

void SLPushBack(SL* ps, SLDateType x)
{
    SLCheckDestroy(ps);

    //ps->a[ps->size] = x;
    //ps->size++;

    SLInsert(ps,ps->size,x);
}

//尾删

void SLPopBack(SL* ps)
{
    assert(ps);


    //温柔型
    //if (ps->size == 0)
    //{
    //    return;
    //}
    
    //暴力型
    //assert(ps->size > 0);

    //ps->size--;

    SLErase(ps, ps->size - 1);
}


//头插

void SLPushFront(SL* ps, SLDateType x)
{
    assert(ps);
    SLCheckDestroy(ps);


    //int i = 0;
    //for (i = 0; i < ps->size ; i++)
    //{
    //    ps->a[ps->size-i] = ps->a[ps->size - i -1];
    //}
    //ps->a[0] = x;
    //ps->size++;


    SLInsert(ps, 0, x);
}

//头删

void SLPopFront(SL* ps)
{
    //防止越界
    assert(ps->size > 0);

    //int i = 0;
    //for (i = 0; i < ps->size - 1; i++)
    //{
    //    ps->a[i] = ps->a[i+1];
    //}
    //ps->size--;

    SLErase(ps, 0);
}

//查找
int SLFind(SL* ps, int n)
{
    int i = 0;
    for (i = 0; i < ps->size; i++)
    {
        if (ps->a[i] == n)
        {
            return i;
        }
    }
    return -1;
}


// 顺序表在pos位置插入x

void SLInsert(SL* ps, int pos, SLDateType x)
{
    assert(ps);
    //=0相当于头插,=size等于尾插
    assert(pos >= 0 && pos <= ps->size);

    SLCheckDestroy(ps);

    int start = ps->size - 1 ;
    while (start >= pos)
    {
        ps->a[start + 1] = ps->a[start];
        start--;
    }
    ps->a[pos] = x;
    ps->size++;
}


// 顺序表删除pos位置的值

void SLErase(SL* ps, int pos)
{
    assert(ps);

    assert(pos >= 0 && pos < ps->size);

    int begin = pos + 1;
    while (begin < ps->size)
    {
        ps->a[begin - 1] = ps->a[begin];
        begin++;
    }
    ps->size--;
}

//顺序表修改
void SLModify(SL* ps, int pos, SLDateType x)
{
    assert(ps);
    assert(pos >= 0 && pos < ps->size);

    ps->a[pos];
}

 值得注意的是:

如果没有使用温柔型或者暴力型判断,可能会发生数组越界,但是一般情况下,编译器不会报错,因为编译器只在数组两天的特定位置放置了越界标记,需要触发才会报错,触发一般是在编译结束时到数组越界标记访问,此时越界了,但没有在此处赋值,也不会报错。

顺序表总结:

缺点:

1.头部和中部插入和删除效率不高O(n);

2.空间不足时,扩容有一定的消耗(尤其是异地扩容)如:开辟空间,拷贝,释放旧空间;

3.扩容逻辑,可能存在空间浪费(200个,但是只用110个)。

优点:

1.尾插尾删足够快;

2.下标的随机访问和修改。

链表

链表的概念及结构:

概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表
中的指针链接次序实现的 。

特点:按需申请释放

逻辑上分析链表如图:

 值得注意:

1.上图,链式结构在逻辑上是连续的,在物理上不一定是连续的;

2.现实中的结点一般是在堆上申请;

3.堆上申请的空间,可能连续,也可能不连续。 

物理上分析链表如下: 

1.单向链表的实现:

// 1 、无头 + 单向 + 非循环链表增删查改实现
typedef int SLTDateType ;
typedef struct SListNode
{
SLTDateType data ;
struct SListNode * next ;
} SListNode ;
// 动态申请一个结点
SListNode * BuySListNode ( SLTDateType x );
// 单链表打印
void SListPrint ( SListNode * plist );
// 单链表尾插
void SListPushBack ( SListNode ** pplist , SLTDateType x );
// 单链表的头插
void SListPushFront ( SListNode ** pplist , SLTDateType x );
// 单链表的尾删
void SListPopBack ( SListNode ** pplist );
// 单链表头删
void SListPopFront ( SListNode ** pplist );
// 单链表查找
SListNode * SListFind ( SListNode * plist , SLTDateType x );
// 单链表在 pos 位置之后插入 x
// 分析思考为什么不在 pos位置之前插入?
void SListInsertAfter ( SListNode * pos , SLTDateType x );
// 单链表删除 pos 位置之后的值
// 分析思考为什么不删除 pos 位置?
void SListEraseAfter ( SListNode * pos );
//销毁
void SListDestory ( SListNode** phead );

 // 动态申请一个结点

SListNode* BuySListNode(SLDataType x)
{

	SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

 // 单链表打印

void SListPrint(SListNode* phead)
{
	SListNode* cur = phead;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

 特别需要注意的是

 

 

上面两张图中,图一说明改变成员,要用成员的指针,

图二说明改变成员的指针,要用成员的指针的指针(二级指针) 

// 单链表尾插

void SListPushBack(SListNode** phead, SLDataType x)
{
	assert(phead);
	SListNode* newnode = BuySListNode(x);

	if (*phead == NULL)
	{
		// 改变的结构体的指针,所以要用二级指针
		*phead = newnode;
	}
	else
	{
		SListNode* tail = *phead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		// 改变的结构体,用结构体的指针即可
		tail->next = newnode;
	}

}

// 单链表的头插

void SListPushFront(SListNode** phead, SLDataType x)
{
	assert(phead);
	SListNode* newnode = BuySListNode(x);
	newnode->next = *phead;
	*phead = newnode;
}

// 单链表的尾删

void SListPopBack(SListNode** phead)
{
	assert(phead);
	//0个
	assert(*phead);

	//1个或以上
	if ((*phead)->next == NULL)
	{
		free(*phead);
		*phead = NULL;
	}
	else
	{
		SListNode* tail = *phead;
		while (tail->next->next)
		{
			tail = tail->next;
		}
		free(tail->next);
		tail->next = NULL;
		
	}
}

// 单链表头删

void SListPopFront(SListNode** phead)
{
	assert(phead);
	assert(*phead);
	
	SListNode* newnode = (*phead)->next;
	free(*phead);
	*phead = newnode;
}

//查找

SListNode* SListFind(SListNode* phead, SLDataType x)
{
	SListNode* newnode = phead;
	while (newnode)
	{
		if (newnode->data == x)
		{
			return newnode;
		}
		
			newnode = newnode->next;
		
	}
	return NULL;
}

//在pos之后插入x 

void SListInsertAfter(SListNode* pos, SLDataType x)
{
	assert(pos);

	SListNode* newnode = BuySListNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
	

}

//在pos之前插x

void SLTInsert(SListNode** phead, SListNode* pos, SLDataType x)
{
	assert(pos);
	//方法一
	if (pos == *phead)
	{
		SListPushFront(phead, x);
	}
	else
	{
		SListNode* tail = *phead;
		while (tail->next != pos)
		{
			tail = tail->next;
		}
		SListNode* newnode = BuySListNode(x);
		tail->next = newnode;
		newnode->next = pos;
	}
	
	//方法二
	//SListNode* tail = *phead;
	//while (newnode->next == NULL)
	//{ 
	//	if (*phead == pos)
	//	{
	//		newnode->next = tail;
	//		*phead = newnode;
	//	}
	//	if (tail->next == pos)
	//	{
	//		newnode->next = tail->next;
	//		tail->next = newnode;
	//	}
	//	else
	//	{
	//		tail = tail->next;
	//	}

	//}
}

// 删除pos位置

void SLTErase(SListNode** phead, SListNode* pos)
{
	assert(phead);
	assert(pos);
	SListNode* tail = *phead;
	if (*phead == pos)
	{
		SListPopFront(phead);
		//*phead = pos->next;
		//return;
	}
	while (tail->next != pos->next)
	{
		if (tail->next == pos)
		{
			tail->next = tail->next->next;
		}
		else
		{
			tail = tail->next;
		}
	}
	free(pos);
	//pos = NULL;//形参不改变实参,在调用外面置空
}

// 删除pos的后一个位置

void SLTEraseAfter(SListNode* pos)
{
	assert(pos);
	assert(pos->next);//如果pos没有下一个,报错

	
	SListNode* postNext = pos->next;
	pos->next = pos->next->next;
	free(postNext);
	postNext = NULL;
}

//销毁 

void SListDestory(SListNode** phead)
{
	assert(phead);

	SListNode* cur = *phead;
	while (cur)
	{
		SListNode* node = cur->next;
		free(cur);
		cur = node;
	}

	*phead = NULL;
}

 替换发删除:

下一个节点的值给pos,然后删除pos->next的节点。

2.双向链表的实现:

// 2 、带头 + 双向 + 循环链表增删查改实现
typedef int LTDataType ;
typedef struct ListNode
{
LTDataType _data ;
struct ListNode * next ;
struct ListNode * prev ;
} ListNode ;
// 创建返回链表的头结点 .
ListNode * ListCreate ();
// 双向链表销毁
void ListDestory ( ListNode * plist );
// 双向链表打印
void ListPrint ( ListNode * plist );
// 双向链表尾插
void ListPushBack ( ListNode * plist , LTDataType x );
// 双向链表尾删
void ListPopBack ( ListNode * plist );
// 双向链表头插
void ListPushFront ( ListNode * plist , LTDataType x );
// 双向链表头删
void ListPopFront ( ListNode * plist );
// 双向链表查找
ListNode * ListFind ( ListNode * plist , LTDataType x );
// 双向链表在 pos 的前面进行插入
void ListInsert ( ListNode * pos , LTDataType x );
// 双向链表删除 pos 位置的结点
void ListErase ( ListNode * pos );

 // 创建返回链表的头结点

ListNode* BuyLTNode(LTDataType x)
{
	ListNode* node = (ListNode*)malloc(sizeof(ListNode));
	if (node == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}

	node->data = x;
	node->next = NULL;
	node->prev = NULL;

	return node;
}


// 创建返回链表的头结点.
ListNode* ListCreate()
{
	ListNode* head = BuyLTNode(0);
	head->next = head;
	head->prev = head;
	return head;
}

// 双向链表打印

// 双向链表打印
void ListPrint(ListNode* pHead)
{
	assert(pHead);
	ListNode* node = pHead->next;
	while (node != pHead)
	{
		printf("%d->",node->data);
		node = node->next;
	}
	printf("NULL\n");
}

// 双向链表在pos的前面进行插入

// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x)
{
	assert(pos);
	ListNode* newnode = BuyLTNode(x);
	ListNode* oldnode = pos->prev;
	newnode->prev = oldnode;
	oldnode->next = newnode;
	newnode->next = pos;
	pos->prev = newnode;

}

// 双向链表删除pos位置的节点

// 双向链表删除pos位置的节点
void ListErase(ListNode* pos)
{
	assert(pos);
	ListNode* oldnode = pos->prev;
	oldnode->next = pos->next;
	pos->next->prev = oldnode;
	free(pos);
}

// 双向链表尾插

// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{
	assert(pHead);
	ListInsert(pHead,x);
}

// 双向链表头插

// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x)
{
	assert(pHead);
	ListInsert(pHead->next,x);
}

// 双向链表尾删

// 双向链表尾删
void ListPopBack(ListNode* pHead)
{
	assert(pHead);
	//
	assert(pHead->next != pHead);
	ListErase(pHead->prev);
}

// 双向链表头删

// 双向链表头删
void ListPopFront(ListNode* pHead)
{
	assert(pHead);
	//
	assert(pHead->next != pHead);
	ListErase(pHead->next);
}

// 双向链表查找

// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x)
{
	assert(pHead);
	ListNode* node = pHead->next;
	while(node != pHead)
	{
		if (node->data == x)
		{
			return node;
		}
		node = node->next;
	}
	return NULL;
}

// 双向链表销毁

// 双向链表销毁
void ListDestory(ListNode* pHead)
{
	assert(pHead);
	ListNode* oldnode = pHead->next;
	while (oldnode != pHead)
	{
		ListNode* oldnode1 = oldnode->next;
		free(oldnode);
		oldnode = oldnode1;
	}
	free(pHead);
	printf("销毁完成!\n");
}

链表和顺序表的区别: 

缓存利用率:

 以上就是个人学习线性表的个人见解和学习的解析,欢迎各位大佬在评论区探讨!

感谢大佬们的一键三连! 感谢大佬们的一键三连! 感谢大佬们的一键三连! 

                                             

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

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

相关文章

YAML资源清单

目录 YAML资源清单 &#xff08;一&#xff09;YAML 语言 &#xff08;1&#xff09;基本语法 &#xff08;2&#xff09;支持的数据结构 &#xff08;二&#xff09;通过资源清单管理容器资源 YAML 语法格式&#xff1a; 创建Service资源清单 &#xff08;三&#xff…

[Docker精进篇] Docker部署和实践 (二)

前言&#xff1a; Docker部署是通过使用Docker容器技术&#xff0c;将应用程序及其所有相关依赖项打包为一个可移植、自包含的镜像&#xff0c;然后在任何支持Docker的环境中快速部署和运行应用程序的过程。 文章目录 Docker部署1️⃣为什么需要&#xff1f;2️⃣有什么作用&am…

【高频面试题】常见技术场景

文章目录 单点登录这块怎么实现的权限认证是如何实现的上传数据的安全性怎么控制&#xff1f;你们项目中日志怎么采集的查看日志的命令生产问题怎么排查怎么快速定位系统的瓶颈 单点登录这块怎么实现的 单点登录的英文名叫做&#xff1a;Single Sign On&#xff08;简称SSO&am…

OpenHarmony Meetup 广州站 OpenHarmony正当时—技术开源

招募令 OpenHarmony Meetup 广州站 火热招募中&#xff0c;等待激情四射的开发者&#xff0c;线下参与OpenHarmonyMeetup线下交流 展示前沿技术、探讨未来可能、让你了解更多专属OpenHarmony的魅力 线下参与&#xff0c;先到先得,仅限20个名额&#xff01; 报名截止时间8月23日…

JS逆向系列之某多多 anti_content

文章目录 声明目标网址anti_content参数分析参考js 环境python 调用测试往期逆向文章推荐声明 本文章中所有内容仅供学习交流,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请私信我立即删除! 目标网址 aHR0cHM6Ly9tb2JpbGUueWFuZ2tlZHVvL…

bigemap如何添加mapbox地图?

第一步 打开浏览器&#xff0c;找到你要访问的地图的URL地址&#xff0c;并且确认可以正常在浏览器中访问&#xff1b;浏览器中不能访问&#xff0c;同样也不能在软件中访问。 以下为常用地图源地址&#xff1a; 天地图&#xff1a; http://map.tianditu.gov.cn 包含&…

Spring整合MyBatis、声明式事务

Spring整合MyBatis 步骤&#xff1a; 导入相关jar包 junitmybatismysqlspring相关aop织入mybatis-spring pom.xml配置文件&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xm…

Docker 镜像

1. 什么是镜像&#xff1f; 镜像 是一种轻量级、可执行的独立软件包&#xff0c;它包含运行某个软件所需的所有内容&#xff0c;我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码、运行时需要的库、环境变量和配置文件等)&#xff0c;这个打包好的运行环境就…

如何使用Redis实现内容推送功能

导读 在日常使用中&#xff0c;我们经常能看见内容推送功能。 常见的场景有&#xff0c;比如你在bilibili关注了某个up主&#xff0c;当up主发布视频后&#xff0c;就会推送到你的收件箱或者是动态中&#xff0c;让粉丝能够及时得知所关注的人发布了内容。 又比如朋友圈&…

离了大谱,这所院校太卷了!524人进复试,刷247人!

一、学校及专业介绍 桂林电子科技大学&#xff08;Guilin University Of Electronic Technology&#xff09;&#xff0c;简称“桂电”、广西一流学科建设高校、是广西唯一拥有国防特色重点专业的高校&#xff0c;是总装备部通信装备预研项目定向发布的30所高校和北斗ICD授权的…

力扣 322. 零钱兑换

题目来源&#xff1a;https://leetcode.cn/problems/coin-change/description/ C题解&#xff08;来源代码随想录&#xff09;&#xff1a;题目中说每种硬币的数量是无限的&#xff0c;可以看出是典型的完全背包问题。动规五部曲分析如下&#xff1a; 确定dp数组以及下标的含义…

从初学者到专家:Java方法的完整指南

目录 一.方法的概念及使用 1.1什么是方法 1.2方法的定义 1.3方法的调用 1.4实参和形参的关系 1.5没有返回值的方法 1.6方法的意义 二.方法重载 2.1方法重载的实现 2.2方法重载的意义 2.3方法签名 一.方法的概念及使用 1.1什么是方法 方法就是一个代码片段. 类似于 …

21款美规奔驰GLS450更换中规高配主机,汉化操作更简单

很多平行进口的奔驰GLS都有这么一个问题&#xff0c;原车的地图在国内定位不了&#xff0c;语音交互功能也识别不了中文&#xff0c;原厂记录仪也减少了&#xff0c;使用起来也是很不方便的。 可以实现以下功能&#xff1a; ①中国地图 ②语音小助手&#xff08;你好&#xf…

内网ip与外网ip

一、关于IP地址 我们平时直接接触最多的是内网IP。而且还可以自己手动修改ip地址。而外网ip&#xff0c;我们很少直接接触&#xff0c;都是间接接触、因为外网ip一般都是运营商管理&#xff0c;而且是全球唯一的&#xff0c;一般我们自己是无法修改的。 内网IP和外网IP是指在…

线程间三种常见的通信手段

线程间通信是指多个线程之间通过某种机制进行协调和交互&#xff0c;例如&#xff1a;线程等待和通知机制就是线程通讯的主要手段之一。 在 Java 中有以下三种实现线程等待的手段 &#xff1a; Object 类提供的 wait()&#xff0c;notify() 和 notifyAll() 方法&#xff1b;C…

Python实现SSA智能麻雀搜索算法优化BP神经网络分类模型(BP神经网络分类算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 麻雀搜索算法(Sparrow Search Algorithm, SSA)是一种新型的群智能优化算法&#xff0c;在2020年提出&a…

新能源电动汽车充电桩控制主板结构组成

你是否好奇过&#xff0c;充电桩主板到底是由哪些部分组成的?又分别是做什么的?今天我们就来一探究竟。 充电桩主板是充电桩的核心部件&#xff0c;它由中央处理器、内存、辅助存储器、输入/输出接口等组成。 中央处理器是充电桩主板的核心&#xff0c;它负责将充电桩的读写指…

vue里搜索框实现防抖功能

进来调用一个闭包函数debounce()&#xff0c;赋值给一个变量debounceFunc&#xff0c;&#xff08;包闭的功能就是说里面的变量timer和参数一直驻留在函数里面&#xff09; input事件调用一个函数debounceFunc&#xff08;&#xff09;&#xff0c;并且传一个回调searchs函数&a…

MATLAB 2023a的机器学习、深度学习实践应用

MATLAB 2023版的深度学习工具箱&#xff0c;提供了完整的工具链&#xff0c;使您能够在一个集成的环境中进行深度学习的建模、训练和部署。与Python相比&#xff0c;MATLAB的语法简洁、易于上手&#xff0c;无需繁琐的配置和安装&#xff0c;让您能够更快地实现深度学习的任务。…

深入理解 go协程 调度机制

Thread VS Groutine 这里主要介绍一下Go的并发协程相比于传统的线程 的不同点&#xff1a; 创建时默认的stack大小 JDK5 以后Java thread stack默认大小为1MC 的thread stack 默认大小为8MGrountine 的 Stack初始化大小为2K 所以Grountine 大批量创建的时候速度会更快 和 …