OJ题目【栈和队列】

题目导入

栈:

  • 题目一:有效的括号
  • 题目二:用栈实现队列

队列

  • 题目:实现循环队列

题目一 有效的括号

题目要求

给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

下图为力扣的示例
在这里插入图片描述
题目代码原型

bool isValid(char* s) {
	//The code is written here
}

这题就很适合用栈来实现,当是左括号的时候就入栈,如果是右括号就与栈顶的左括号进行对比,如果匹配成功就将栈顶的左括号给Pop掉
创建栈

    Stack st;
    StackInit(&st);

入栈函数:

 if (*s == '(' || *s == '[' || *s == '{')
 {
     StackPush(&st, *s);
 }

但是匹配了没有意义,因为栈内可能还有多个元素,所以我们要判断不匹配的情况(不匹配可以直接出结果)
代码如下:

 else
 {
     STDataType tmp = StackTop(&st);
     StackPop(&st);
     if ((tmp == '(' && *s != ')') ||
         (tmp == '[' && *s != ']') ||
         (tmp == '{' && *s != '}'))
     {
         StackDestroy(&st);
         return false;
     }
 }

这是判断一次,题目的s不可能就这这么点字符,所以我们要使用循环

    while (*s)
    {
        if (*s == '(' || *s == '[' || *s == '{')
        {
            StackPush(&st, *s);
        }
        else
        {
            STDataType tmp = StackTop(&st);
            StackPop(&st);
            if ((tmp == '(' && *s != ')') ||
                (tmp == '[' && *s != ']') ||
                (tmp == '{' && *s != '}'))
            {
                StackDestroy(&st);
                return false;
            }
        }
        s++;
    }

循环走出来了,就代表s已经走到\0了,这时候我们就需要判断栈内是否还有元素,如果还有就代表s并不是一个有效的字符串(有效字符串需满足:每个右括号都有一个对应的相同类型的左括号。)
代码如下

    if (!StackEmpty(&st))//栈为非空,还有元素
    {
        StackDestroy(&st);
        return false;
    }
    StackDestroy(&st);
    return true;

这样大体就写完了,但是这还有个问题:s的第一个元素就是右括号该怎么办?
其实很简单,当s的第一个元素就是右括号的时候,就代表s并不是一个有效的字符串,并且这时候的栈是空的,所以我们只需要对栈进行判空操作就好了。

    while (*s)
    {
        if (*s == '(' || *s == '[' || *s == '{')
        {
            StackPush(&st, *s);
        }
        else
        {
            if (StackEmpty(&st))//当s的第一个元素就是右括号
            {
                StackDestroy(&st);
                return false;
            }
            STDataType tmp = StackTop(&st);
            StackPop(&st);
            if ((tmp == '(' && *s != ')') ||
                (tmp == '[' && *s != ']') ||
                (tmp == '{' && *s != '}'))
            {
                StackDestroy(&st);
                return false;
            }
        }
       

完整代码:

bool isValid(char* s) {
    Stack st;//创建栈
    StackInit(&st);
    while (*s)
    {
        if (*s == '(' || *s == '[' || *s == '{')
        {
            StackPush(&st, *s);
        }
        else
        {
            if (StackEmpty(&st))
            {
                StackDestroy(&st);
                return false;
            }
            //方法一
            STDataType tmp = StackTop(&st);
            StackPop(&st);
            if ((tmp == '(' && *s != ')') ||
                (tmp == '[' && *s != ']') ||
                (tmp == '{' && *s != '}'))
            {
                StackDestroy(&st);
                return false;
            }
            
            //方法二(任选其一)
            if ((StackTop(&st) == '(' && *s != ')') ||
                (StackTop(&st) == '[' && *s != ']') ||
                (StackTop(&st) == '{' && *s != '}'))
            {
                StackDestroy(&st);
                return false;
            }
            else
            {
            	StackPop(&st);
            }
        }
        s++;
    }
    if (!StackEmpty(&st))
    {
        StackDestroy(&st);
        return false;
    }
    StackDestroy(&st);
    return true;
}

在函数结束先,将自己在该函数开辟的空间个释放掉,这是一个好习惯。

题目二 用栈实现队列

在这里插入图片描述
队列是先进先出,栈是先进后出,这题我们就需要使用两个栈来实现了。
先入栈的元素是在栈底,而先出的元素是在栈顶,所以我们把有元素的栈里面的元素入到没有元素的栈里面,就能完成队列的出队操作,类似下图
在这里插入图片描述

我们入队列(用栈实现的)是入到有元素的栈里面,因为我将数据入到非空栈的时候是入到栈顶的,当我要进行出队列的时候,是将栈下标一及以后的元素入到空栈,再将非空栈的栈底元素Pop掉
在这里插入图片描述

peek的要求是返回队列开头的元素,这样我们直接返回非空栈中下标为0的元素。

完整代码

// 支持动态增长的栈
typedef int STDataType;
typedef struct Stack
{
	STDataType* _a;
	int _top;		// 栈顶
	int _capacity;  // 容量 
}Stack;

// 初始化栈 
void StackInit(Stack* ps)
{
	assert(ps);
	ps->_a = NULL;
	ps->_top = 0;
	ps->_capacity = 0;
}


// 入栈 
void StackPush(Stack* ps, STDataType data)
{
	if (ps->_top == ps->_capacity)
	{
		int _NewCapacity = ps->_capacity == 0 ? 4 : ps->_capacity * 2;
		STDataType* _tmp = (STDataType*)realloc(ps->_a, _NewCapacity * sizeof(STDataType));
		ps->_a = _tmp;
		ps->_capacity = _NewCapacity;
	}
	ps->_a[ps->_top++] = data;
}


// 出栈 
void StackPop(Stack* ps)
{
	assert(ps && ps->_top > 0);
	ps->_top--;
}


// 获取栈顶元素 
STDataType StackTop(Stack* ps)
{
	assert(ps && ps->_top > 0);
	return ps->_a[ps->_top - 1];
}


// 获取栈中有效元素个数 
int StackSize(Stack* ps)
{
	assert(ps && ps->_top > 0);
	return ps->_top;
}


// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
int StackEmpty(Stack* ps)
{
	return (ps->_top == 0);
}


// 销毁栈 
void StackDestroy(Stack* ps)
{
	free(ps->_a);
	ps->_a = NULL;
	ps->_top = ps->_capacity = 0;
}

typedef struct {
    Stack s1;
    Stack s2;
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
    StackInit(&(obj->s1));
    StackInit(&(obj->s2));

    return obj;
}

void myQueuePush(MyQueue* obj, int x) {
    if(!StackEmpty(&obj->s1))
    {
        StackPush(&obj->s1,x);
    }
    else
    {
        StackPush(&obj->s2,x);
    }
    
}

int myQueuePop(MyQueue* obj) {
	//假设法
    Stack* Empty = &obj->s1;
    Stack* NotEmpty = &obj->s2;
    if(!StackEmpty(Empty))
    {
        Empty = &obj->s2;
        NotEmpty = &obj->s1;
    }
    
    int top = StackSize(NotEmpty);
    int tmp = 1;
    while(tmp != top)
    {
        StackPush(Empty,NotEmpty->_a[tmp++]);
        StackPop(NotEmpty);
    }
    int val = StackTop(NotEmpty);
    StackPop(NotEmpty);
    return val;
}

int myQueuePeek(MyQueue* obj)
{
    if(!StackEmpty(&obj->s1))
    {
        return obj->s1._a[0];
    }
    else
    {
        return obj->s2._a[0];
    }

}

bool myQueueEmpty(MyQueue* obj) {
    return StackEmpty(&obj->s1) && StackEmpty(&obj->s2);
}

void myQueueFree(MyQueue* obj) {
    StackDestroy(&obj->s1);
    StackDestroy(&obj->s2);
    free(obj);

    obj = NULL;
}

队列

题目:实现循环队列

在这里插入图片描述
循环队列可以用数组和链表来实现,本文是用数组实现。
可能有很多人看到题目就设计一个数组,定一个headtailhead或者tail到了数组结尾的时候,就绕回到数组开头。
在这里插入图片描述

但是这里有个问题:我的判空和判满该这么区分呢?
判空很简单,判断head是否等于tail,是的话就是空。但是,在这个数组中,判满的逻辑也是判断head是否等于tail。
这种情况也别称为假溢出。

这时候我们就有两种方法来解决。

  • 第一种:使用一个size来记录,数组元素的个数,如果等于数组长度就是满,如果等于零就是空
  • 第二种:在开辟数组的时候多开一个空间,这个空间在逻辑上是不存放数组的,这里的不存放是说在存放数据的时候,就是有某块空间不存放数据,并不是多开的那个空间不存放数据。如下图在这里插入图片描述

如图所示,当判满成立的时候,就是有某块空间不存放数据,上图tail所指向的空间,那里面的元素已经被我Pop掉了,已经不认为是队列内的元素了
所以方法二也可以将判满和判空给区分开来

判满:看tail+1是否等于head(当然要解决回绕的问题)
判空就还是看tail是否等于head。

本文使用的是第二种方法。

循环队列的创建(myCircularQueueCreate)

假设队列的长度为k

typedef struct {
    int * _a;
    int _head;
    int _tail;
    int _k; //该队列的长度
} MyCircularQueue;

MyCircularQueue* myCircularQueueCreate(int k) {
	//先开辟队列
    MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    //再开辟队列的数组部分
    obj->_a = (int*)malloc(sizeof(int)* (k+1));//多开一个空间
    obj->_head = obj->_tail = 0;
    obj->_k = k;//将队列长度k赋值给我的_k
    return obj;
}

注:因为力扣上的动态开辟基本不会报错,所以可以省略判断开辟成功的步骤(在日常敲代码的时候还是判断比较好)

解决回绕问题:

当我的tail等于k+1的时候,直接取模就好了
当然也可以暴力一点,不管tail的值,直接取模

obj->_tail %= obj->_k+1;

所以我们就可以直接写判空和判满的代码了:

//判空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->_head == obj->_tail;
}

//判满
bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return (obj->_tail+1) % (obj->k+1) == obj->_head;
}

入队列(myCircularQueueEnQueue)

题目代码:

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    
}

题目对这段代码的要求: 向循环队列插入一个元素。如果成功插入则返回真。

那么插入不成功就返回假(队列满了就不能插入了)
所以可以直接调用判满函数

if(myCircularQueueIsFull(obj))
{
	return false;
}

如果没满,就继续插入,然后解决回绕问题,也可以使用暴力方法(不管tail的大小,直接%上k+1)

//插入数据
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))
    {
        return false;
    }

    obj->_a[obj->_tail++] = value;
    //方法一(暴力)
    obj->_tail %= (obj->_k+1);
	
	//方法二(判断)
	if(obj->_tail == obj->_k+1)
    {
        obj->_tail = 0;
    }
    return true;
}

出队列(myCircularQueueDeQueue)

题目代码:

//删除数据
bool myCircularQueueDeQueue(MyCircularQueue* obj) {

}

题目对这段代码的要求:从循环队列中删除一个元素。如果成功删除则返回真。

那么删除不成功就返回假(队列空了就不能插入了)
所以可以直接调用判空函数

    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }

因为队列是先进先出(FIFO),所以我们继续出队列的时候并不是对tail操作,而是对head操作。
出队列的时候直接++head就好了(当然也要解决回绕问题)。
解决回绕问题和入队列的操作是一样的。

//删除数据
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    obj->_head++;
    obj->_head %= (obj->_k + 1);
    return true;
    
}

取队头元素(myCircularQueueFront)

题目对这个函数的要求:从队首获取元素。如果队列为空,返回 -1 。
直接返回head位置的元素就好了

//取队头元素
int myCircularQueueFront(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->_a[obj->_head];
}

取队尾元素(myCircularQueueRear)

题目对这个函数的要求:获取队尾元素。如果队列为空,返回 -1 。

注意:我这里的tail其实是指向待插入数据的空间,也就是最后一个元素的下一个空间。
所以我们返回尾元素,其实是返回tail的前一个空间。
一般情况下只需要返回tail - 1就可以了,但是,有一种特殊情况,就是当入完队列后我的tail进行了回绕,这时候tail0,我这时返回tail - 1的元素就会造成越界。在这里插入图片描述
有两种方法处理

  • 第一种:判断tail是否等于0,是的话返回下标为 k 个元素。
  • 第二种:先tail-1然后加上k+1%k+1,这种方法不需要判断tail,可以直接返回值。
//第一种
return obj->_a[obj->_tail == 0 ? k ; obj->_tail-1];

//第二种
return obj->_a[(obj->_tail-1 + obj->_k+1) %  (obj->_k+1)]

第二种方法解决正常情况
将tail=3带入,k=5带入

((3-1) + (5+1)) % (5+1)
= (2+6) % 6
= 8 % 6
= 2

第二种方法解决特殊情况
将tail=0带入,k=5带入

((0-1) + (5+1)) % (5+1)
= (-1+6) % 6
= 5 % 6
= 5

所以第二种也可以写成这样

return obj->_a[(obj->_tail + obj->_k) %  (obj->_k+1)]// -1 和 1 抵消了

函数代码如下

//取队尾元素
int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->_a[(obj->_tail - 1 + obj->_k + 1) % (obj->_k + 1)];
}

销毁循环队列(myCircularQueueFree)

从内到外释放,先释放内部,再释放外部。

//销毁队列
void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->_a);
    obj->_a = NULL;
    obj->_head = obj->_tail = obj->_k = 0;
    free(obj);
}

完整代码

typedef struct {
    int * _a;
    int _head;
    int _tail;
    int _k; 
} MyCircularQueue;

//创建循环队列
MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    obj->_a = (int*)malloc(sizeof(int)* (k+1));
    obj->_head = obj->_tail = 0;
    obj->_k = k;
    return obj;
}

//判空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->_head == obj->_tail;
}

//判满
bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return (obj->_tail+1) % (obj->_k + 1) == obj->_head;
}


//插入数据
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))
    {
        return false;
    }

    obj->_a[obj->_tail++] = value;
    //obj->_tail %= (obj->_k+1);
    if(obj->_tail == obj->_k+1)
    {
        obj->_tail = 0;
    }
    return true;
}

//删除数据
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    obj->_head++;
    obj->_head %= (obj->_k + 1);
    return true;
    
}

//取队头元素
int myCircularQueueFront(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->_a[obj->_head];
}

//取队尾元素
int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->_a[(obj->_tail - 1 + obj->_k + 1) % (obj->_k + 1)];
}


//销毁队列
void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->_a);
    obj->_a = NULL;
    obj->_head = obj->_tail = obj->_k = 0;
    free(obj);
}

结语

最后感谢您能阅读完此片文章,如果有任何建议或纠正欢迎在评论区留言,也可以前往我的主页看更多好文哦(点击此处跳转到主页)。
如果您认为这篇文章对您有所收获,点一个小小的赞就是我创作的巨大动力,谢谢!!!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

四川汇聚荣聚荣科技有限公司正规吗?

在当今数字化时代,科技公司如雨后春笋般涌现,而四川汇聚荣聚荣科技有限公司作为其中的一员,其正规性自然成为外界关注的焦点。接下来的内容将围绕这一问题展开深入探讨。 一、公司概况四川汇聚荣聚荣科技有限公司是一家位于成都的高新技术企业…

兆易创新:周期已至 触底反弹?

韩国那边来的数据啊,4月芯片库存同比下降33.7%,创近10年以来(最)大降幅,芯片出口同比增长53.9%,其中存储芯片出口额同比大幅增长98.7%,开启了涨价模式。沉寂一年多的存储芯片迎来了景气周期。 所…

IO进程线程(五)库的制作、进程

文章目录 一、库(一)静态库1. 概念2. 制作3. 使用(编译)(1)生成可执行文件(2)运行 (二)动态库(共享库)1. 概念2. 制作3. 生成可执行文…

9. MySQL事务、字符集

文章目录 【 1. 事务 Transaction 】1.1 事务的基本原理1.2 MySQL 执行事务的语法和流程1.2.1 开始事务1.2.2 提交事务1.2.3 回滚(撤销)事务实例1:一致性实例2:原子性 【 2. 字符集 和 校对规则 】2.1 基本原理2.2 查看字符集查看…

Web3.0区块链技术开发方案丨NFT项目开发

在Web3.0时代,非同质化代币(NFT)的概念正在引领着数字资产领域的变革和创新。NFT作为区块链上的数字资产,具有独一无二的特性,可以代表任何形式的数字或实物资产,并在区块链上进行唯一标识和交易。本文将探…

ElementUI中date-picker组件,怎么给选择一个月份范围中大写月份改为阿拉伯数组月份(例如:一月、二月,改为1月、2月)

要将 Element UI 的 <el-date-picker> 组件中的月份名称从中文大写&#xff08;如 "一月", "二月"&#xff09;更改为阿拉伯数字&#xff08;如 "1月", "2月"&#xff09;&#xff0c;需要进行一些定制化处理。可以通过国际化&a…

php项目加密源码

软件简介 压缩包里有多少个php就会被加密多少个PHP、php无需安装任何插件。源码全开源 如果上传的压缩包里有子文件夹&#xff08;子文件夹里的php文件也会被加密&#xff09;&#xff0c;加密后的压缩包需要先修复一下&#xff0c;步骤&#xff1a;打开压缩包 》 工具 》 修…

如何找出你的Windows 10的内部版本和版本号?这里提供两种方法

你过去可能没有真正考虑过Windows内部版本号,除非这是你工作的一部分。以下是如何了解你运行的Windows 10的内部版本、版本和版本号。 内部版本意味着什么 Windows一直使用内部版本。它们代表着对Windows的重大更新。传统上,大多数人都是根据他们使用的主要命名版本(Windo…

Docker大学生看了都会系列(二、2.2CentOS安装Docker)

系列文章目录 第一章 Docker介绍 第二章 2.1 Mac通过Homebrew安装Docker 第二章 2.2 CentOS安装Docker 第三章 Docker常用命令 文章目录 一、前言二、环境三、CentOS安装Docker3.1 系统要求3.2 卸载旧的版本3.3 安装yum工具包3.4 设置Docker的镜像源3.5 安装Docker3.6 关闭防火…

新手教程之使用LLaMa-Factory微调LLaMa3

文章目录 为什么要用LLaMa-Factory什么是LLaMa-FactoryLLaMa-Factory环境搭建微调LLaMA3参考博文 为什么要用LLaMa-Factory 如果你尝试过微调大模型&#xff0c;你就会知道&#xff0c;大模型的环境配置是非常繁琐的&#xff0c;需要安装大量的第三方库和依赖&#xff0c;甚至…

滤波算法[2]----理解离散贝叶斯滤波器(上)

离散过滤器(Discrete Filter) 为了方便对离散贝叶斯过滤器的理解&#xff0c;开始使用了下面的一个例子&#xff0c;十分形象生动的阐述了离散贝叶斯的原理&#xff0c;以及实现过程。 虽然我本篇博客的目的不是为了直接对书进行翻译&#xff0c;但是这个例子很妙&#xff0c;…

WebStorm 2024.1.1 Mac激活码 前端开发工具集成开发环境(IDE)

WebStorm 2024 Mac激活码 搜索Mac软件之家下载WebStorm 2024 Mac激活版 WebStorm 2024 功能介绍 WebStorm 2024是由JetBrains公司开发的一款专为前端开发设计的集成开发环境&#xff08;IDE&#xff09;。它提供了一整套功能&#xff0c;旨在提高Web开发者的工作效率和代码质…

Nextjs使用教程

一.手动创建项目 建议看这个中文网站文档,这个里面的案例配置都是手动的,也可以往下看我这个博客一步步操作 1.在目录下执行下面命令,初始化package.json文件 npm init -y2.安装react相关包以及next包 yarn add next react react-dom // 或者 npm install --save next react…

特步公主与七匹狼公子举行婚礼:“校服是你,婚纱也是你”!95后“二代”们开始接班?

从校服到婚纱&#xff0c;两位福建晋江系企业的“二代”上演了一出豪门青梅竹马的网络小说情节。 6月1日是个有意思的日子&#xff0c;有人庆祝儿童节&#xff0c;有人举办婚礼。 当天晚上&#xff0c;特步集团“小公主”丁佳敏在其社交媒体平台官宣了喜讯&#xff0c;并且晒…

重磅消息! Stable Diffusion 3将于6月12日开源 2B 版本的模型,文中附候补注册链接。

在OpenAI发布Sora后&#xff0c;Stability AI也发布了其最新的模型Stabled Diffusion3, 之前的文章中已经和大家介绍过&#xff0c;感兴趣的小伙伴可以点击以下链接阅读。Sora是音视频方向&#xff0c;Stabled Diffusion3是图像生成方向&#xff0c;那么两者没有必然的联系&…

Nginx在线部署和离线部署方式

Nginx 有两种安装方式: 1)在线安装的方式 1.添加Nginx 到yum源 sudo rpm -Uvh <http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm> 2.安装Nginx,直接使用yum方式 yum install -y nginx 3.启动nginx,刚安装的nginx不…

AI程序员来了,大批码农要失业

根据GitHub发布的《Octoverse 2021年度报告》&#xff0c;2021年中国有755万程序员&#xff0c;排名全球第二。 ChatGPT的出现&#xff0c;堪比在全球互联网行业点燃了一枚“核弹”&#xff0c;很多人都会担心“自己的工作会不会被AI取代”。 而2024年的AI进展速度如火箭般&am…

搭建chattts应用,做文字转语音

下载代码 git clone https://github.com/2noise/ChatTTS.git下载endpoint并上传&#xff1a; https://huggingface.co/2Noise/ChatTTS/tree/main 将上面下载的文件上传到服务器上 修改webui.py 更改为本地模型地址 import os import random import argparseimport torch i…

Java常规题技术分享

一、数组排序和添加成员 设计类Student和类StudentClass。 (1) 类Student有字符串属性name、double属性grade和int属性age 有带参数的构造方法&#xff0c;可设置三个属性的值 有各个属性的置取方法 (2)类StudentClass有Student数组属性stus存放班级成员&#xff0c;有int…

【ARM Cache 与 MMU 系列文章 7.6 -- ARMv8 MMU 相关寄存器介绍】

文章目录 MMU 转换控制寄存器 TCR_ELxTCR_ELx 概览TCR_ELx 寄存器字段详解TCR 使用示例Normal MemoryCacheableShareability MMU 内存属性寄存器 MAIR_ELx寄存器结构内存属性字段使用实例 MMU 地址翻译表基址寄存器 TTBR0/1_ELxTTBR0_ELx 寄存器概述寄存器结构功能和用途编程示…