详解堆栈的几种实现方法——C语言版
堆排序法c语言代码

堆排序法c语言代码堆排序法是一种常用的排序算法,它的特点是时间复杂度为O(nlogn),适用于大数据量的排序。
下面是使用C语言实现的堆排序算法。
1.原理堆排序法的基本思想是将待排序的序列构成一棵完全二叉树,并满足每个节点的值都大于/小于其子节点的值。
首先需要构建一个最大堆顶,将数组的首位和最后一个元素交换,然后将序列长度减一,再将已排序的序列构建堆顶,交换首位元素,以此类推,直到序列长度为一。
最终得到的排序序列就是按照升序或降序排列的。
2.实现#include <stdio.h>#include <stdlib.h>void head_adjust(int arr[], int start, int end);void heap_sort(int arr[], int len);int main(){int arr[] = {5, 9, 1, 4, 2, 8, 0, 3, 6, 7};int len = sizeof(arr) / sizeof(arr[0]);heap_sort(arr, len);for(int i=0; i<len; i++){printf("%d ", arr[i]);}return 0;}/*建立大根堆*/void head_adjust(int arr[], int start, int end){int dad = start;int son = dad*2 + 1;while(son <= end){if(son + 1 <= end && arr[son] < arr[son+1]) {son++;}if(arr[dad] > arr[son]){return;}else{int temp = arr[dad];arr[dad] = arr[son];arr[son] = temp;dad = son;son = dad*2 + 1;}}}/*堆排序*/void heap_sort(int arr[], int len) {for(int i = len/2-1; i>=0; i--) {head_adjust(arr, i, len-1); }for(int i =len-1; i>0; i--){int temp = arr[i];arr[i] = arr[0];arr[0] = temp;head_adjust(arr, 0, i-1);}}3.算法分析时间复杂度:O(nlogn)空间复杂度:O(1)稳定性:不稳定排序方法(可能会交换值相同的元素的相对位置)堆排序法适合数据量较大的排序任务,但在数据量较小时,实现的效率不如插入排序或快速排序。
数据结构——用C语言描述(第3版)教学课件第3章 栈和队列

if(S->top==-1) /*栈为空*/
return(FALSE);
else
{*x = S->elem[S->top];
return(TRUE);
}
返回主目录}[注意]:在实现GetTop操作时,也可将参数说明SeqStack *S 改为SeqStack S,也就是将传地址改为传值方式。传 值比传地址容易理解,但传地址比传值更节省时间、 空间。
返回主目录
算法:
void BracketMatch(char *str) {Stack S; int i; char ch; InitStack(&S); For(i=0; str[i]!='\0'; i++) {switch(str[i])
{case '(': case '[': case '{':
3.1.3 栈的应用举例
1. 括号匹配问题
思想:在检验算法中设置一个栈,若读入的是左括号, 则直接入栈,等待相匹配的同类右括号;若读入的是 右括号,且与当前栈顶的左括号同类型,则二者匹配, 将栈顶的左括号出栈,否则属于不合法的情况。另外, 如果输入序列已读尽,而栈中仍有等待匹配的左括号, 或者读入了一个右括号,而栈中已无等待匹配的左括 号,均属不合法的情况。当输入序列和栈同时变为空 时,说明所有括号完全匹配。
return(TRUE);
}
返回主目录
【思考题】
如果将可利用的空闲结点空间组织成链栈来管理,则申 请一个新结点(类似C语言中的malloc函数)相当于链 栈的什么操作?归还一个无用结点(类似C语言中的 free函数)相当于链栈的什么操作?试分别写出从链栈 中申请一个新结点和归还一个空闲结点的算法。
【数据结构】堆栈的基本操作

【数据结构】堆栈的基本操作堆栈的概念:是⼀组相同类型数据的集合,并且拥有后进先出的特点,所有的操作都在堆栈顶端进⾏。
堆栈的基本操作:Init 创建⼀个空堆栈Push 把数据压⼊堆栈顶端Pop 从堆栈顶弹出数据Top 从栈顶取数据Empty 判断堆栈是否为空堆栈,是则返回true,否则返回falseFull 判断栈是否为满,是则返回true,否则返回false⽤数组实现堆栈:1 typedef struct st_stack{2int size;3int *data;4int top;5 }T_Stack;67int StackInit( T_Stack *ptStack, int *data, int size)8 {9 ptStack->size = size;10 ptStack->data = data;11 ptStack->top = 0;1213return0;14 }1516int StackPush( T_Stack *ptStack, int data )17 {18if( ptStack->top == ptStack->size )19 {20return -1;21 }2223 ptStack->data[ptStack->top++] = data;2425return0;26 }2728int StackPop( T_Stack *ptStack, int *data )29 {30if( ptStack->top == 0 )31 {32return -1;33 }3435 *data = ptStack->data[--ptStack->top];3637return0;38 }3940int StackTop( T_Stack *ptStack, int *data )41 {42if( ptStack->top == 0 )43 {44return -1;45 }4647 *data = ptStack->data[ptStack->top - 1];4849return0;50 }5152int StackIsEmpty( T_Stack *ptStack )53 {54return ( ptStack->top == 0 );55 }5657int StackIsFull( T_Stack *ptStack )58 {59return ( ptStack->top == ptStack->size );60 }。
实验报告堆栈操作

一、实验目的1. 理解堆栈的基本概念和原理;2. 掌握堆栈的基本操作,包括入栈、出栈、取栈顶元素等;3. 熟悉堆栈在编程中的应用,提高编程能力。
二、实验原理堆栈是一种后进先出(Last In First Out, LIFO)的数据结构,它由一系列元素组成,遵循“先进后出”的原则。
在堆栈中,新元素总是被添加到栈顶,而移除元素时,总是从栈顶开始。
堆栈的基本操作包括:1. 初始化:创建一个空堆栈;2. 入栈:将一个元素添加到堆栈的顶部;3. 出栈:从堆栈中移除顶部元素;4. 取栈顶元素:获取堆栈顶部的元素,但不从堆栈中移除;5. 判断堆栈是否为空:检查堆栈中是否还有元素。
三、实验器材1. 计算机软件:C/C++编译器;2. 程序代码编辑器:例如Visual Studio、Code::Blocks等。
四、实验步骤1. 初始化堆栈:创建一个空堆栈,并设置栈的最大容量。
2. 入栈操作:(1)检查堆栈是否已满,如果已满,则无法入栈;(2)将元素添加到堆栈的顶部。
3. 出栈操作:(1)检查堆栈是否为空,如果为空,则无法出栈;(2)从堆栈中移除顶部元素。
4. 取栈顶元素操作:(1)检查堆栈是否为空,如果为空,则无法取栈顶元素;(2)获取堆栈顶部的元素。
5. 判断堆栈是否为空操作:(1)检查堆栈中的元素个数,如果为0,则堆栈为空。
6. 编写程序实现上述操作,并进行测试。
五、实验结果与分析1. 初始化堆栈:创建一个最大容量为10的空堆栈。
2. 入栈操作:(1)入栈元素1,堆栈状态:[1];(2)入栈元素2,堆栈状态:[1, 2];(3)入栈元素3,堆栈状态:[1, 2, 3]。
3. 出栈操作:(1)出栈元素3,堆栈状态:[1, 2];(2)出栈元素2,堆栈状态:[1]。
4. 取栈顶元素操作:(1)取栈顶元素1,栈顶元素为1。
5. 判断堆栈是否为空操作:(1)判断堆栈是否为空,结果为“否”。
六、实验结论通过本次实验,我们掌握了堆栈的基本概念、原理和操作。
堆栈的工作原理

堆栈的工作原理
堆栈是一种数据结构,它遵循“先进后出”(LIFO)的原则。
它通常用于存储和管理函数调用、中断处理、内存分配等操作。
堆栈的工作原理如下:
1. 初始化堆栈:在使用堆栈之前,需要先分配一块固定大小的内存空间来存储堆栈中的元素。
这个空间可以是数组、链表或是其他数据结构。
2. 压栈(Push)操作:当有新的元素要加入堆栈时,它将被放置在堆栈的顶部。
这个过程被称为“压栈”,也就是将元素插入到堆栈的顶部。
3. 弹栈(Pop)操作:当需要访问堆栈中的元素时,可以从堆
栈的顶部开始弹出元素。
每次弹出的元素都是最新加入堆栈的那个元素,所以堆栈遵循了“先进后出”的原则。
4. 栈顶指针:堆栈通常使用一个指针来跟踪堆栈顶部的位置。
压栈操作会将栈顶指针向上移动,而弹栈操作会将栈顶指针向下移动。
5. 栈溢出:如果堆栈已满时还尝试进行压栈操作,就会发生栈溢出的错误。
栈溢出意味着堆栈已经超出了它的容量限制。
6. 栈空:如果堆栈中没有元素时,就称为栈空。
这时进行弹栈操作会导致错误,因为没有可弹出的元素。
堆栈的工作原理简单明了,它提供了一个高效的方式来存储和访问数据。
通过遵循“先进后出”的原则,堆栈可以灵活地支持各种场景下的数据管理需求。
堆栈及静态数据区详解

堆、栈及静态数据区详解五大内存分区在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。
里面的变量通常是局部变量、函数参数等。
堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。
如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free 来结束自己的生命的。
全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改,而且方法很多)明确区分堆与栈在bbs上,堆与栈的区分问题,似乎是一个永恒的话题,由此可见,初学者对此往往是混淆不清的,所以我决定拿他第一个开刀。
首先,我们举一个例子:void f() { int* p=new int[5]; }这条短短的一句话就包含了堆与栈,看到new,我们首先就应该想到,我们分配了一块堆内存,那么指针p呢?他分配的是一块栈内存,所以这句话的意思就是:在栈内存中存放了一个指向一块堆内存的指针p。
在程序会先确定在堆中分配内存的大小,然后调用operator new分配内存,然后返回这块内存的首地址,放入栈中,他在VC6下的汇编代码如下:00401028 push 14h0040102A call operator new (00401060)0040102F add esp,400401032 mov dword ptr [ebp-8],eax00401035 mov eax,dword ptr [ebp-8]00401038 mov dword ptr [ebp-4],eax这里,我们为了简单并没有释放内存,那么该怎么去释放呢?是delete p么?澳,错了,应该是delete []p,这是为了告诉编译器:我删除的是一个数组,VC6就会根据相应的Cookie 信息去进行释放内存的工作。
C语言实现堆栈(自己的)

C语⾔实现堆栈(⾃⼰的)stack.h#ifndef __STACK_H__#define __STACK_H__#include <stdio.h>#include <stdlib.h>#include <stdbool.h>typedef int ElementType;struct SNode {ElementType *Data; /* 存储元素的数组 */int Top; /* 栈顶指针 */int MaxSize; /* 堆栈最⼤容量 */};typedef struct SNode *Stack;Stack CreateStack( int MaxSize ); //建⽴结构体堆栈bool IsFull( Stack S ); //判断堆栈是是否溢出bool Push( Stack S, ElementType X ); //压栈bool IsEmpty( Stack S ); //判断堆栈是是否为空ElementType Pop( Stack S ); //出栈#endifstack.c#include "stack.h"#include "sys.h"u8 Choose_Stack_Flag=0; //未检测到加减符号时候,0:⼀个结构体,检测到1:另⼀个结构体Stack CreateStack( int MaxSize ){Stack S = (Stack)malloc(sizeof(struct SNode));S->Data = (ElementType *)malloc(MaxSize * sizeof(ElementType));S->Top = -1;S->MaxSize = MaxSize;return S;}bool IsFull( Stack S ){return (S->Top == S->MaxSize-1);}bool Push( Stack S, ElementType X ){if ( IsFull(S) ) {printf("堆栈满");return false;}else {S->Data[++(S->Top)] = X;return true;}}bool IsEmpty( Stack S ){return (S->Top == -1);}ElementType Pop( Stack S ){if ( IsEmpty(S) ) {printf("堆栈空");return ERROR; /* ERROR是ElementType的特殊值,标志错误 ERROR 0 */}elsereturn ( S->Data[(S->Top)--] );}。
汇编语言堆栈指令

汇编语言堆栈指令汇编语言是一种底层的计算机语言,它直接操作计算机的硬件。
在汇编语言中,堆栈(Stack)是一种重要的数据结构,用于存储程序执行时的临时数据和返回地址等信息。
堆栈指令用于操作堆栈,包括入栈、出栈、压栈和弹栈等操作。
本文将从堆栈指令的角度介绍汇编语言的相关知识。
一、入栈指令入栈指令用于将数据压入堆栈,常用的入栈指令有PUSH和PUSHA。
PUSH指令可以将立即数或寄存器中的值压入堆栈,而PUSHA指令可以将通用寄存器中的值一次性压入堆栈。
入栈指令的作用是保存临时数据,以便后续的操作使用。
二、出栈指令出栈指令用于将数据从堆栈中弹出,常用的出栈指令有POP和POPA。
POP指令可以将堆栈顶部的数据弹出并存入指定的寄存器,而POPA 指令可以一次性将堆栈中的数据弹出并存入通用寄存器。
出栈指令的作用是恢复之前保存的数据,以便继续执行程序。
三、堆栈指针堆栈指针(Stack Pointer)是一个特殊的寄存器,用于指示当前堆栈的顶部位置。
在x86架构中,堆栈指针通常用ESP表示。
入栈和出栈指令会自动更新堆栈指针的值,以保证数据正确地压入和弹出堆栈。
四、压栈和弹栈压栈和弹栈是堆栈操作中的两个重要概念。
压栈(Push)指的是将数据从数据段移动到堆栈段的过程,堆栈指针会自动减小。
弹栈(Pop)指的是将数据从堆栈段移动到数据段的过程,堆栈指针会自动增加。
压栈和弹栈是堆栈操作的基本操作,用于实现数据的存储和读取。
五、堆栈的应用堆栈在汇编语言中有着广泛的应用,它可以用于实现函数的调用和返回、保存寄存器的状态、传递参数和局部变量等。
函数的调用和返回是汇编语言程序中常见的操作,它们依赖于堆栈来传递参数和保存返回地址。
当一个函数被调用时,参数会被压入堆栈,函数执行完毕后,返回地址会从堆栈中弹出,程序继续执行返回地址指向的位置。
堆栈还可以用于保存寄存器的状态。
在汇编语言中,为了保护现场,程序在执行前会将当前寄存器的值保存到堆栈中,执行完毕后再将堆栈中的值恢复到寄存器中。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
详解堆栈的几种实现方法——C语言版基本的抽象数据类型(ADT)是编写C程序必要的过程,这类ADT有链表、堆栈、队列和树等,本文主要讲解下堆栈的几种实现方法以及他们的优缺点。
堆栈(stack)的显著特点是后进先出(Last-In First-Out, LIFO),其实现的方法有三种可选方案:静态数组、动态分配的数组、动态分配的链式结构。
静态数组:特点是要求结构的长度固定,而且长度在编译时候就得确定。
其优点是结构简单,实现起来方便而不容易出错。
而缺点就是不够灵活以及固定长度不容易控制,适用于知道明确长度的场合。
动态数组:特点是长度可以在运行时候才确定以及可以更改原来数组的长度。
优点是灵活,缺点是由此会增加程序的复杂性。
链式结构:特点是无长度上线,需要的时候再申请分配内存空间,可最大程度上实现灵活性。
缺点是链式结构的链接字段需要消耗一定的内存,在链式结构中访问一个特定元素的效率不如数组。
首先先确定一个堆栈接口的头文件,里面包含了各个方案下的函数原型,放在一起是为了实现程序的模块化以及便于修改。
然后再接着分别介绍各个方案的具体实施方法。
堆栈接口stack.h文件代码:[cpp]view plaincopy1./*2.** 堆栈模块的接口 stack.h3.*/4.#include<stdlib.h>5.6.#define STACK_TYPE int /* 堆栈所存储的值的数据类型 */7.8./*9.** 函数原型:create_stack10.** 创建堆栈,参数指定堆栈可以保存多少个元素。
11.** 注意:此函数只适用于动态分配数组形式的堆栈。
12.*/13.void create_stack(size_t size);14.15./*16.** 函数原型:destroy_stack17.** 销毁一个堆栈,释放堆栈所适用的内存。
18.** 注意:此函数只适用于动态分配数组和链式结构的堆栈。
19.*/20.void destroy_stack(void);21.22./*23.** 函数原型:push24.** 将一个新值压入堆栈中,参数是被压入的值。
25.*/26.void push(STACK_TYPE value);27.28./*29.** 函数原型:pop30.** 弹出堆栈中栈顶的一个值,并丢弃。
31.*/32.void pop(void);33.34./*35.** 函数原型:top36.** 返回堆栈顶部元素的值,但不改变堆栈结构。
37.*/38.STACK_TYPE top(void);39.40./*41.** 函数原型:is_empty42.** 如果堆栈为空,返回TRUE,否则返回FALSE。
43.*/44.int is_empty(void);45.46./*47.** 函数原型:is_full48.** 如果堆栈为满,返回TRUE,否则返回FALSE。
49.*/50.int is_full(void);一、静态数组堆栈在静态数组堆栈中,STACK_SIZE表示堆栈所能存储的元素的最大值,用top_element 作为数组下标来表示堆栈里面的元素,当top_element == -1的时候表示堆栈为空;当top_element == STACK_SIZE - 1的时候表示堆栈为满。
push的时候top_element加1,top_element == 0时表示第一个堆栈元素;pop的时候top_element减1。
a_stack.c 源代码如下:[cpp]view plaincopy1./*2.**3.** 静态数组实现堆栈程序 a_stack.c ,数组长度由#define确定4.*/5.6.#include"stack.h"7.#include<assert.h>8.#include<stdio.h>9.10.#define STACK_SIZE 100 /* 堆栈最大容纳元素数量 */11.12./*13.** 存储堆栈中的数组和一个指向堆栈顶部元素的指针14.*/15.static STACK_TYPE stack[STACK_SIZE];16.static int top_element = -1;17.18./* push */19.void push(STACK_TYPE value)20.{21. assert(!is_full()); /* 压入堆栈之前先判断是否堆栈已满*/22. top_element += 1;23. stack[top_element] = value;24.}25.26./* pop */27.void pop(void)28.{29. assert(!is_empty()); /* 弹出堆栈之前先判断是否堆栈已空 */30. top_element -= 1;31.}32.33./* top */34.STACK_TYPE top(void)35.{36. assert(!is_empty());37.return stack[top_element];38.}39.40./* is_empty */41.int is_empty(void)42.{43.return top_element == -1;44.}45.46./* is_full */47.int is_full(void)48.{49.return top_element == STACK_SIZE - 1;50.}51.52./*53.** 定义一个print函数,用来打印堆栈里面的元素。
54.*/55.void print(void)56.{57.int i;58. i = top_element;59. printf("打印出静态数组堆栈里面的值: ");60.if(i == -1)61. printf("这是个空堆栈\n");62.while(i!= -1)63. printf("%d ",stack[i--]);64. printf("\n");65.}66.int main(void)67.{68. print();69. push(10); push(9); push(7); push(6); push(5);70. push(4); push(3); push(2); push(1); push(0);71. printf("push压入数值后:\n");72. print();73. printf("\n");74. pop();75. pop();76. printf("经过pop弹出几个元素后的堆栈元素:\n");77. print();78. printf("\n");79. printf("top()调用出来的值: %d\n",top());80.return 1;81.}结果如下图:二、动态数组堆栈头文件还是用stack.h,改动的并不是很多,增加了stack_size变量取代STACK_SIZE 来保存堆栈的长度,数组由一个指针来代替,在全局变量下缺省为0。
create_stack函数首先检查堆栈是否已经创建,然后才分配所需数量的内存并检查分配是否成功。
destroy_stack函数首先检查堆栈是否存在,已经释放内存之后把长度和指针变量重新设置为零。
is_empty 和is_full 函数中添加了一条断言,防止任何堆栈函数在堆栈被创建之前就被调用。
d_stack.c源代码如下:[cpp]view plaincopy1./*2.** 动态分配数组实现的堆栈程序 d_stack.c3.** 堆栈的长度在创建堆栈的函数被调用时候给出,该函数必须在任何其他操作堆栈的函数被调用之前条用。
4.*/5.#include"stack.h"6.#include<stdio.h>7.#include<malloc.h>8.#include<assert.h>9.10./*11.** 用于存储堆栈元素的数组和指向堆栈顶部元素的指针12.*/13.static STACK_TYPE *stack;14.static int stack_size;15.static int top_element = -1;16.17./* create_stack */18.void create_stack(size_t size)19.{20. assert(stack_size == 0);21. stack_size = size;22. stack = (STACK_TYPE *)malloc(stack_size * sizeof(STACK_TYPE));23.if(stack == NULL)24. perror("malloc分配失败");25.}26.27./* destroy */28.void destroy_stack(void)29.{30. assert(stack_size > 0);31. stack_size = 0;32. free(stack);33. stack = NULL;34.}35.36./* push */37.void push(STACK_TYPE value)38.{39. assert(!is_full());40. top_element += 1;41. stack[top_element] = value;42.}43.44./* pop */45.void pop(void)46.{47. assert(!is_empty());48. top_element -= 1;49.}50.51./* top */52.STACK_TYPE top(void)53.{54. assert(!is_empty());55.return stack[top_element];56.}57.58./* is_empty */59.int is_empty(void)60.{61. assert(stack_size > 0);62.return top_element == -1;63.}64.65./* is_full */66.int is_full(void)67.{68. assert(stack_size > 0);69.return top_element == stack_size - 1;70.}71.72.73./*74.** 定义一个print函数,用来打印堆栈里面的元素。