数据结构--链栈的c语言实现

Stack(堆栈):一种操作受限制的线性表,只允许在一头进行添加和删除

定义:
        · “栈”也叫“堆栈”,是一种操作受限的线性表,栈只允许在线性表的一端进行插入/删除等操作,不允许其他位置插入/删除
        · 线性表中可以进行插入/删除的一端称为:栈顶(top),栈顶保存的元素为“栈顶元素”,相对另一端称为“栈底”(bottom)
        · 如果栈中没有数据称为“空栈”
        · 向栈中插入元素,称为“进栈/入栈/压栈”,从栈中删除元素称为“退栈/出栈/弹栈”;
        · 栈的插入/删除操作只允许在栈顶进行,后进栈的元素必定先出栈,称为:后进先出表LIFO;

堆栈抽象数据类型的定义:
    ADT Stack{
        数据对象 : D={a0,a1,a2...,an, 其中ai(i=1,2..n)是同一种数据类型的元素}
        数据关系 : R={<ai,ai+1>}
        基本操作:
            InitStack(&S):        初始化栈,分配内存空间
            DestroyStack(&S):    销毁并释放栈的内存
            ClearStack(&S):        清空栈
            IsEmpty(S):            判断栈是否为空
            GetSize(S):            返回栈元素个数
            Peek(S):            偷看栈顶元素
            Push(&S,e):            压栈、入栈
            Pop(&S,&e):            弹栈、出栈
            Traverse(S):        从栈底到栈顶依次遍历
    }ADT Stack;

卡特兰数:如果有n个不同元素进栈,出栈元素不同的排列的个数为:1/(n+1)    *    Cⁿ2n

(还有一种栈叫“共享栈”,逻辑上是2个栈,物理上共享一片连续的内存)

栈的顺序实现:
    顺序栈一般通过数组实现;堆栈的操作都在栈顶完成,选择数组中索引值较大的一端作为栈顶,也就是数组尾部作为栈顶;

栈的链式实现:
    使用链表作为栈的存储结构,称为链栈;链栈只允许在线性表的一端进行操作,可以选择链表的头部作为栈顶,不管是入栈/出栈都在链表的头节点上进行;

链栈的代码:

//不带头结点的链栈,缺点是获取栈的大小不方便
#define ElemType int
#include <stdio.h>
#include <stdlib.h>

typedef struct Node{		//单链表的节点
	ElemType data;			//数据域
	struct Node* next;		//指针域
}Node,Stack;

// InitStack(&S):		初始化栈
void InitStack(Stack** s){
	*s = NULL;	
}

// DestroyStack(&S):	销毁并释放栈的内存
void DestroyStack(Stack** s){
	//空栈,*s没指向任何Node,直接返回
	if(*s == NULL) return;
	//栈非空,层层销毁
	Stack* p;//临时指针p
	while((*s)->next != NULL){//若Node的next指针非空,进入循环进行删除
		p = *s;
		*s = (*s)->next;
		printf("删除节点\n");
		free(p);
	}
	//删完之后,此时只剩头节点,将头节点删除
	printf("删除节点\n");
	free(*s);
	*s = NULL;//头指针置空
}

// IsEmpty(S):			判断栈是否为空
int IsEmpty(Stack* s){//栈空返回1
	return s == NULL;
}

// GetSize(S):			返回栈元素个数
int GetSize(Stack* s){
	Stack* p = s;
	int count = 0;
	while(p!=NULL){
		count++;
		p = p->next;
	}
	return count;
}

// Peek(S):			偷看栈顶元素
ElemType Peek(Stack* s){
	if( IsEmpty(s) ){
		exit(1);
	}
	return s->data;
}

// Push(&S,e):			压栈,成功返回1
int Push(Stack** s, ElemType e){
	Node* newNode = (Node*) malloc(sizeof(Node));
	if(newNode == NULL){ exit(1); }

	newNode->data = e;
	newNode->next = *s;//使新节点的next指向栈顶元素
	//更改栈顶指针
	*s = newNode;
	return 1;
}

// Pop(&S,&e):			弹栈,并返回该元素
ElemType Pop(Stack** s){
	//空栈,弹栈失败并提示信息
	if( IsEmpty(*s) ){
		printf("Failure, Empty Stack!");
		exit(1);
	}

	//临时指针p,指向旧的栈顶位置
	Stack* p = *s;
	//保存栈顶元素ret
	ElemType ret = (*s)->data;
	//更新栈顶指针
	*s = (*s)->next;
	//弹栈并返回
	free(p);
	return ret;
}

// Traverse(S):		从栈顶依次遍历
void Traverse(Stack* s){
	printf("\n");
	Stack* p = s;
	while(p!=NULL){
		printf("%d  ", p->data);
		p = p->next;
	}
	printf("\n");
}

//=============测试程序==============================================================
int main(int argc, char const *argv[])
{
	Stack* stack;
	InitStack(&stack);
	//遍历
	Traverse(stack);

	printf("is IsEmpty:%d\n", IsEmpty(stack));
	Push(&stack, 6);
	Push(&stack, 16);
	Push(&stack, 26);
	Push(&stack, 36);
	Push(&stack, 46);
	//遍历
	Traverse(stack);
	printf("栈大小为:%d\n", GetSize(stack));

	printf("栈顶元素为:%d\n", Peek(stack));

	printf("弹出了:%d\n", Pop(&stack));
	printf("弹出了:%d\n", Pop(&stack));
	printf("弹出了:%d\n", Pop(&stack));
	printf("is IsEmpty:%d\n", IsEmpty(stack));
	printf("栈大小为:%d\n", GetSize(stack));
	//遍历
	Traverse(stack);

	//销毁栈
	DestroyStack(&stack);
	Traverse(stack);
	printf("is IsEmpty%d\n", IsEmpty(stack));

	return 0;
}

运行结果:

结论:c语言实现的链表结构,如果只设置一个结构体来表示链表和结点,虽然省了一个结构体,但是需要双重指针,且获取栈的大小不方便。

---------------------------------------------

以上内容并不完善,欢迎评论指正补充,共同进步OwO ~~

  • 8
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个C语言链栈实现数制转换的示例代码: ``` #include <stdio.h> #include <stdlib.h> #define STACK_INIT_SIZE 100 #define STACK_INCREMENT 10 typedef struct StackNode { int data; struct StackNode *next; } StackNode, *LinkStackPtr; typedef struct { LinkStackPtr top; int stack_size; } LinkStack; void InitStack(LinkStack *S) { S->top = NULL; S->stack_size = 0; } int StackEmpty(LinkStack *S) { if (S->top == NULL) { return 1; } else { return 0; } } void Push(LinkStack *S, int e) { StackNode *p = (StackNode *)malloc(sizeof(StackNode)); p->data = e; p->next = S->top; S->top = p; S->stack_size++; } int Pop(LinkStack *S, int *e) { if (StackEmpty(S)) { return 0; } StackNode *p = S->top; *e = p->data; S->top = p->next; free(p); S->stack_size--; return 1; } int GetTop(LinkStack *S, int *e) { if (StackEmpty(S)) { return 0; } *e = S->top->data; return 1; } void Convert(int n, int radix) { LinkStack S; InitStack(&S); while (n != 0) { Push(&S, n % radix); n = n / radix; } while (!StackEmpty(&S)) { int e; Pop(&S, &e); if (e < 10) { printf("%d", e); } else { printf("%c", e - 10 + 'A'); } } printf("\n"); } int main() { int n, radix; printf("Enter an integer: "); scanf("%d", &n); printf("Enter the radix: "); scanf("%d", &radix); printf("The converted number is: "); Convert(n, radix); return 0; } ``` 在这个示例代码中,我们首先定义了一个链栈数据结构,包括链栈节点的数据结构链栈数据结构。然后我们实现链栈的基本操作,包括初始化、判断是否为空、入栈、出栈、获取栈顶元素等操作。 最后,我们使用链栈实现了数制转换的功能。具体来说,我们将需要转换的整数不断除以进制数,将得到的余数入栈。然后我们不断出栈,将出栈的元素转换为对应的进制数的字符,最终输出结果。在输出结果时,如果余数小于10,直接输出数字;如果余数大于等于10,转换为对应的大写字母输出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值