必不可少需要掌握的嵌入式知识(2) -- 经典数据结构总结之 (链表,队列)
2019独角兽企业重金招聘Python工程师标准>>>
数据结构:
定义:
数据结构是计算机组织,存储数据的方式。数据结构是指相互之间存在一种或多种特定关系的元素集合,大部分的数据结构的实现都需要借助C语言中的指针和结构体类型。
几种常见的数据结构:
1,线性数据结构:元素之间一般存在一对一关系,是最常用的一种数据结构,比如:数组,栈,队列和线性表。
2,树形数据结构:结点间具有层次关系,每一层的结点能且只能和上一层的一个结点相关,但同时可以和下一层的多个结点相关,称为一对多关系,比如:树,堆
3,图形结构:允许多个结点之间相关,被称为多对多关系,分为有向图和多向图。
下面对这几种数据结构做简单介绍:
数组:存放着一组相同类型的数据,需要预先指定数组的长度,有一维,二维,多维数组。
链表:是C语言中一种应用广泛的数据结构,它采用动态分配内存的方式实现,用一组任意的存储单元存放数据元素,一般为每个数据元素增加指针域,用来指向后继元素。
数组和链表的区别:
从逻辑结构来看:数组必须事先定义固定的长度,不能适应数据动态的增减的情况;链表进行动态的内存分配,可以适应数据动态的增减情况,且可以方便的插入删除数据项(数组中插入删除数据项时,需要移动其他数据项)
从内存存储来看:(静态)数组从栈中分配内存(用NEW分配在堆中),对于程序员方便快捷,但自由度小;链表在堆中分配内存,自由度大但申请管理比较麻烦
从访问方式来看:数组在内存中是连续存储的,因此可以利用下标索引进行随机访问;链表是链式存储结构,在访问数据的时候只能通过线性的方式由前到后顺序访问,所以访问效率比数组低。
栈、队列、线性表:可采取顺序存储和链式存储的方法进行存储。
顺序存储:借助数据元素在存储空间中的相对位置来表示元素之间的逻辑关系
链式存储:借助表示数据元素存储地址的指针表示元素之间的逻辑关系
栈:只允许在序列末端进行操作,栈的操作只能在栈顶进行,一般栈又被称为后进先出或先进后出的线性结构。
顺序栈:采用顺序存储结构的栈称为顺序栈,即需要用一片地址连续的空间来存储栈的元素,顺序栈的类型定义如下:
typedef struct{
ElemType *elem; //存储空间的基址
int top; //栈顶元素的下一个元素,简称栈顶位标
int size; //当前分配的存储容量
int increment; //扩容时增加的存储容量
}SqStack;
链栈:采用链式存储结构的栈称为链栈:
typedef struct LsNode{
ElemType data; //数据域
struct LSNode *next; //指针域
}LSNode, *LsStack; //结点和链栈类型
链栈使用C语言的实现如下所示:
/*
The realization of the stack.
*/
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
//Define the node struct.
typedef struct Node
{
int data; //Data.
struct Node *pNext; //Pointer the next node.
}NODE, *PNODE; //NODE is equivalent to Node,PNODE is equivalent to struct Node *.
//定义栈的结构体
typedef struct Stack
{
PNODE pTop; //栈顶结点
PNODE pBottom; //栈底结点
}STACK, *PSTACK;
//Function declarations
void initStack (PSTACK pStack); //初始化栈函数
void pushStack (PSTACK pStack, int val); //入栈函数
int popStack (PSTACK pStack, int *pVal); //出栈函数
void traverseStack (PSTACK pStack); //遍历栈的函数
int isEmpty (PSTACK pStack); //判断栈是否为空的函数
void clearStack (PSTACK pStack); //清空栈的函数
int main (void)
{
STACK stack; //定义一个栈变量
int val; //用来保存出栈的内容
initStack (&stack); //调用初始化栈函数
pushStack (&stack, 10); //调用入栈函数
pushStack (&stack, 20); //调用入栈函数
pushStack (&stack, 30); //调用入栈函数
pushStack (&stack, 40); //调用入栈函数
pushStack (&stack, 50); //调用入栈函数
traverseStack (&stack); //调用遍历栈的函数
//调用出栈的函数
if (popStack (&stack, &val))
printf ("出栈失败!\n");
else
printf ("出栈成功,出栈元素值为:%d.\n", val);
//调用清空栈的函数
clearStack (&stack);
traverseStack (&stack);
return 0;
}
void initStack (PSTACK pStack)
{
pStack->pTop = (PNODE)malloc(sizeof(NODE)); //创建一个空结点,让 pTOP 指向它
if (NULL != pStack->pTop)
{
pStack->pBottom = pStack->pTop; //将 pBottom 也指向空结点
pStack->pTop->pNext = NULL; //清空空结点的指针欲
}
else //如果分配内存失败
{
printf ("内存分配失败,程序退出!\n");
exit (-1);
}
return ;
}
void pushStack (PSTACK pStack, int val)
{
PNODE pNew = (PNODE)malloc (sizeof (NODE)); //动态创建一个新结点
pNew->data = val; //设置新结点的数据域的值
pNew->pNext = pStack->pTop; //将新结点的指针域指向之前的栈顶结点
pStack->pTop = pNew; //pTop 指向新的结点
return ;
}
int popStack (PSTACK pStack, int *pVal)
{
if (isEmpty (pStack))
return -1;
else
{
//先保存栈顶元素的地址,然后将 pTop 指向下一元素,最后释放之前栈顶元素的内存
PNODE tmpNode = pStack->pTop;
*pVal = pStack->pTop->data;
pStack->pTop = pStack->pTop->pNext;
free (tmpNode);
tmpNode = NULL;
}
return 0;
}
void traverseStack (PSTACK pStack)
{
PNODE tmpNode = pStack->pTop; //将栈顶赋给一个临时结点,因为在遍历栈的时候不能销毁栈
//循环遍历栈,直到栈底
while (tmpNode != pStack->pBottom)
{
printf ("%d ", tmpNode->data);
tmpNode = tmpNode->pNext;
}
printf ("\n");
return ;
}
int isEmpty (PSTACK pStack)
{
if (pStack->pTop == pStack->pBottom)
return -1;
else
return 0;
}
void clearStack (PSTACK pStack)
{
//栈为空则推出该函数
if (isEmpty (pStack))
return ;
else
{
PNODE p1 = pStack->pTop;
PNODE p2 = NULL;
//循环释放内存
while (p1 != pStack->pBottom)
{
p2 = p1->pNext;
free (p1);
p1 = p2;
}
//将栈顶和栈底指向同一个指针域为空的结点
pStack->pTop = pStack->pBottom;
}
return ;
}
队列:只允许在序列两端进行操作,一般队列也被称为先进先出的线性结构
循环队列:采用顺序存储结构的队列,需要按队列可能的最大长度分配存储空间,其类型定义如下:
typedef struct
{
Elemtype *base; //存储空间的基址
int front; //队头位标
int rear; //队尾位标,指示队尾元素的下一位置
int maxSize; //maxSize
}SqQueue;
链队列:采用链式存储结构的队列称为链队列,一般需要设置头尾指针:
typedef struct LQNode
{
Elemtype data; //数据域
struct LQNode *next; //指针域
}LQNode, *QueuePtr; //结点和链栈类型
typedef struct
{
QueuePtr front; //队头指针
QueuePtr rear; //队尾指针
}LQueue; //栈队列类型
以下为链队列的实现:
/*
The realization of the queue.
*/
#include <stdio.h>
#include <stdlib.h>
typedef int ElementType;
typedef struct QNode
{
ElementType Element; //数据域
struct QNode *pNext; //指向下一个元素的指针域
}QNode, *QNodePtr;
typedef struct Node
{
QNodePtr front; //队列头
QNodePtr rear; //队列尾
}Node, *NodePtr;
ElementType isEmpty (NodePtr pNode); /*判断一个队列是否为空*/
NodePtr CreateQueue (void); /*创建一个队列*/
void DisposeQueue (NodePtr pNode); /*销毁队列*/
void MakeEmpty (NodePtr pNode); /*清空队列*/
void Enqueue (ElementType x, NodePtr pNode); /*入队*/
ElementType Front (NodePtr pNode); /*若队列不为空,返回头元素数据域*/
void Dequeue (NodePtr pNode); /*若队列不为空,则删除头元素*/
ElementType FrontAndDequeue (NodePtr pNode); /*返回队列中每个元素的数据域*/
ElementType isEmpty (NodePtr pNode)
{
return pNode->front == pNode->rear;
}
NodePtr CreateQueue (void)
{
NodePtr pNode;
pNode = (NodePtr)malloc (sizeof (Node));
pNode->front = pNode->rear = (QNodePtr)malloc (sizeof (QNode));
if (!pNode->front)
{
printf ("out of space! CreateQueue failed!\n");
return NULL;
}
pNode->front->pNext = NULL;
return pNode;
}
void MakeEmpty (NodePtr pNode)
{
if (NULL == pNode)
{
printf ("Must user CreateQueue first\n");
return ;
}
else
while (!isEmpty (pNode))
Dequeue (pNode);
}
void DisposeQueue (NodePtr pNode)
{
while (pNode->front)
{
pNode->rear = pNode->front->pNext;
free (pNode->front);
pNode->front = pNode->rear;
}
printf ("\nDispose queue completed!!!");
}
void Enqueue (ElementType x, NodePtr pNode)
{
QNodePtr p = (QNodePtr)malloc (sizeof (QNode));
if (!p)
{
printf ("Out of space!\n");
return ;
}
p->Element = x;
p->pNext = NULL;
pNode->rear->pNext = p;
pNode->rear=p;
}
ElementType Front (NodePtr pNode)
{
if (!isEmpty (pNode))
return pNode->front->pNext->Element;
return 0; /*Return value used to avoid warning*/
}
void Dequeue (NodePtr pNode)
{
if (!isEmpty (pNode))
{
QNodePtr p = (QNodePtr)malloc (sizeof (QNode));
if (!pNode)
{
printf ("Out of place!--Dequeue\n");
return ;
}
p = pNode->front->pNext;
pNode->front->pNext = p->pNext;
if (pNode->rear == p)
pNode->rear = pNode->front;
free (p);
}
}
/*
获取队列元素中的数据元素
*/
ElementType FrontAndDequeue (NodePtr pNode)
{
if (!isEmpty (pNode))
{
QNodePtr p = (QNodePtr)malloc (sizeof (QNode));
if (!p)
{
printf ("Out of space!--FrontAndDequeue\n");
return ;
}
p = pNode->front->pNext;
ElementType temp;
temp = p->Element;
pNode->front->pNext = p->pNext;
if (pNode->rear == p)
pNode->rear = pNode->front;
free (p);
return temp;
}
printf ("Empty queue!\n");
return 0; /*Return value used to avoid warning*/
}
int main (void)
{
int n, num, m;
int i;
NodePtr pNode = CreateQueue ();
printf ("initialization complete.\n");
if (isEmpty(pNode))
printf ("queue is empty!\n");
printf ("Please input the number of elements in the queue:\n");
scanf ("%d", &n);
printf ("Please input %d elements put in queue:", n);
for (i = 0; i < n; i++)
{
scanf ("%d", &num);
Enqueue (num, pNode);
}
printf ("Front element:%d.\n", Front(pNode));
printf ("Element is queue:");
while (!isEmpty (pNode))
printf ("%3d", FrontAndDequeue (pNode));
DisposeQueue (pNode);
printf ("\n");
return 0;
}
转载于:https://my.oschina.net/xolsenberg/blog/756573
必不可少需要掌握的嵌入式知识(2) -- 经典数据结构总结之 (链表,队列)相关推荐
- 嵌入式工程师的经典面试题目及答案
上个星期,去深圳一家搞ARM开发的公司面试,HR叫我做了一份卷子,里面都是C编程,心中暗喜,因为这些题基本上都在程序员面试宝典里见过.后来回到学校,在网上搜索,原来这些题都是嵌入式工程师的经典面试题目 ...
- 嵌入式工程师的经典面试题目
嵌入式工程师的经典面试题目 预处理器(Preprocessor) 1 . 用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题) #define SECONDS ...
- 嵌入式Linux入门经典笔记
史上最牛的Linux内核学习方法论 点击下载 我的arm_linux移植笔记 点击下载 S3C2440完全开发流程 点击下载 Linux系统命令及其使用详解完整版 点击 ...
- ARM+linux+2440嵌入式开发相关经典书籍(转)
源:ARM+linux+2440嵌入式开发相关经典书籍 转载于:https://www.cnblogs.com/LittleTiger/p/7992971.html
- 哪些因素不会限制linux服务器并发,嵌入式技术工程师 经典面试题(含答案)
嵌入式技术工程师 经典面试题(含答案) 来源 : 未知 2016-01-14 1.int main(){ int a;float b,c; scanf("%2d%3f%4f" ...
- c语言程序设计基础1千克,c语言学习知识编程经典编辑题汇总整编.doc
c语言学习知识编程经典编辑题汇总整编.doc - C语言编程基础习题汇总1.设计一个由键盘输入三个整数,求这三个数的平均数的程序.2.编写一个程序,用于水果店售货员结账.已知苹果每斤2.50元,鸭梨每 ...
- 嵌入式知识概要(1)
1.嵌入式软硬件关系图 2.嵌入式知识框图 3.C语言与数据结构
- 嵌入式知识-ARM裸机-学习笔记(2):利用GPIO来控制LED(附mkv210_image.c文件解析)
嵌入式知识-ARM裸机-学习笔记(2):利用GPIO来控制LED(附mkv210_image.c文件解析) 首先声明该博客是针对朱有鹏老师的嵌入式课程进行笔记的总结. 一.通过GPIO控制点亮LED( ...
- 嵌入式知识-ARM裸机-学习笔记(9):SD卡启动详解(S5PV210)
嵌入式知识-ARM裸机-学习笔记(9):SD卡启动详解(S5PV210) 一.SD卡介绍 1. SD卡背景知识和特点 SD卡.MMC卡.MicroSD.TF卡:这些卡其实内部就是Flash存储颗粒,比 ...
- 嵌入式Linux学习经典书籍-学完你就是高手
很多刚入门的朋友一直都有人问我要学习资料,嵌入式实在太杂,网上很多人写的太不负责了,本书单综合了本人以及一些朋友多年的经验整理而成. 本人见识和阅读量有限,本书单可能有不对的地方,欢迎朋友指正,交流你 ...
最新文章
- Linux shell 学习笔记(1)— 文件和目录(查看、创建、复制、软硬链接、重命名及删除操作)
- 刚刚,谷歌终于回应AI专利争议:怕被碰瓷,抢先下手,永不牟利
- 图像的放大与缩小(2)——双线性插值放大与均值缩小
- 【转载】尝试使用GraphicsMagick的缩略图功能
- int、unsigned int、float、double 和 char 在内存中存储方式
- iOS开发常用的资源和资料
- 火狐和chrome_Firefox,Chrome和Edge都将支持WebAuthn的硬件两因素身份验证
- DSO(dsoframer)的接口文档
- concurrency runtime学习笔记之二:并行
- NginxWebUI - 图形化的 Nginx 配置管理工具
- python加密狗的制作_制作u盘加密狗
- 软件测试工程师需要掌握哪些技能呢?
- 冒险岛 PHP,php基础知识
- 记录贴/阴阳师core loop
- Sam Altman 山姆奥特曼:How To Invest In Startups如何投资初创公司
- BPI-M1P(全志A20)刷Android启动卡之后启动的过程
- 低学历可以学习IT技术吗?
- 蓝桥杯 拉马车 java_拉马车蓝桥杯(基于Java中的stack和queue)
- 西语加计算机专业怎么样,如何在电脑上添加西班牙语输入法?
- 水晶报表 发布 部署
热门文章
- access denied (java.io.FilePermission IKAnalyzer.cfg.xml read
- java 线程池 连接池_浅析Tomcat高并发之连接池、线程池
- 转载:相同版本的JVM和Java应用,在 x86 和AArch64 平台性能相差30%
- 某文件在桌面上,命令窗口中找不到,因为桌面是两个目录合成的
- LINUX终端可以使用reset清除所有输出
- 为什么安装了增强功能,VirtualBox菜单自动调整显示尺寸还是灰色,不能用
- WINDOWS NPAPI插件小结
- 热烈庆祝博客排名进入前一万(8448)
- 06_day初始化PIC
- 网吧电脑显示连不上服务器,Pubwin客户机连不上服务器怎么办?