IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 数据结构栈的基本操作(C语言) -> 正文阅读

[数据结构与算法]数据结构栈的基本操作(C语言)

要求:

1.采用顺序存储实现栈的初始化、入栈、出栈操作。
2.采用链式存储实现栈的初始化、入栈、出栈操作。
3.写一个程序,将输入的十进制数据M 转换为八进制数据M8,将其调试通过。
在此基础上修改程序,实现十进制数据M 向N 进制(2或8或16)的转换。
(1)采用顺序存储结构实现栈。
(2)采用链表结构实现栈。
?

?其实就是单链表和顺序表的应用,效果如图:

?代码及详情如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>

#define MaxSize 100	//栈的最大存储值
typedef int ElemType;	
typedef struct SqStack {	//顺序栈
	ElemType data[MaxSize];//数据
	int top;	//栈顶指针
}Sq;
Sq s;	

typedef struct LinkNode {	//链表
	ElemType data;
	struct LinkNode* next;
}Lnode;
typedef struct LinkStack {	//链栈
	Lnode* top;
}Ls;
Ls L;
Ls* l = &L;
int count = 0;	//用来计数,判断栈是否创建过或者是否初始化过,避免二次创建或初始化

//函数声明
void InitStrack(int i);
void CreateStrack(int i);
void PrintStack(int i);
void F(int i,int n);
int F1(int count);
void Push(int i,int m);
void Pop(int i);
void GetTop(int i);
void TransFrom(int i);
void menu();
void menu1();
void menu2();
void menu3();
void Delte(int i);
void transfrom(int n);

int main() {
	system("title 栈的操作");
	int chose = 0;
	while (1) {
		menu();	//菜单
		scanf("%d", &chose);	//选择
		switch (chose) {
		case 1:
			system("cls");	//清屏
			menu1();	//进入顺序栈的菜单
			count = 0;	//这里主要是为了在建立完顺序栈后退出重置,以至于链栈能正常建立
			break;	
		case 2:
			system("cls");	//同上
			menu2();	//进入链栈的菜单
			count = 0;	//退出链栈的菜单后,重置
			break;
		case 3:
			TransFrom(1);	//利用栈来转换进制
			break;
		case 0: return;	//退出
		default:printf("输入错误,重新输入:\n");
		}
	}
	return 0;
}
//初始菜单
void menu() {
	printf("··········\n");
	printf("·   栈的操作     ·\n");
	printf("·   1、顺序栈    ·\n");
	printf("·   2、链栈      ·\n");
	printf("·   3、进制转换  ·\n");
	printf("·   0、退出      ·\n");
	printf("··········\n");
	printf("请选择:\n");
}

//顺序栈菜单
void menu1() {
	int n;
	while (1) {
		printf("+++++++++++++++++\n");
		printf("+ 顺序栈的操作  +\n");
		/*因为两个菜单的主要内容都一样,只有菜单头不同,所以单打一份菜单头*/
		menu3();	//显示主菜单
		scanf("%d", &n);	//选择功能
		if (n == 0) {		//选择0退出
			system("cls");	//清屏
			return;
		}
		F(1,n);	//菜单选择项的功能的调用,这里的1代表着 顺序栈
	}
}
//链表栈菜单
void menu2() {
	int n;
	while (1) {
		printf("+++++++++++++++++\n");
		printf("+ 链栈的操作    +\n");
		menu3();	//显示主菜单
		scanf("%d", &n);	//输入选择
		if (n == 0) {		//选择0退出
			system("cls");	//清屏
			return;
		}
		F(2,n);	//菜单选择项的功能的调用,这里的2代表着 链栈
	}
}
//主菜单
void menu3() {
	printf("+ 1、创建栈     +\n");
	printf("+ 2、初始化     +\n");
	printf("+ 3、打印栈     +\n");
	printf("+ 4、进栈       +\n");
	printf("+ 5、出栈       +\n");
	printf("+ 6、取栈顶元素 +\n");
	printf("+ 7、清空栈     +\n");
	printf("+ 0、返回上一级 +\n");
	printf("+++++++++++++++++\n");
	printf("请选择:\n");
}
//菜单选择项的功能的调用
/*因为两个栈方法我都写在一个函数里,所有定义个i变量来区分执行哪一个的操作*/
void F(int i,int n) {	//i是表示1,2的,就是表示链栈还是顺序栈,
	if (i ==  1) {
		switch (n) {	//全程序的1都是代表顺序栈
		case 1:CreateStrack(1); break;	//创建
		case 2:InitStrack(1); break;	//初始化
		case 3:PrintStack(1); break;	//打印
		case 4:	
			if (F1(count) == 0) {
				break;
			}
			printf("请输入要放入栈的元素:\n");
			int n;
			scanf("%d", &n); 
			Push(1,n);break;	//压栈,n是要放进去的元素
			/*因为进制转换需要用到Push函数,但又不需要前面这些话语,
			所以这些语句写在调用函数前*/
		case 5:Pop(1);break;	//出栈
		case 6:GetTop(1); break;	//求栈顶元素
		case 7:Delte(1); break;	//清空栈
		default:  printf("输入错误!\n"); break;
		}
		return;
	}
	if (i == 2) {	//这里是代表着链表,下面均与上同
		/*两个链表不同的地方只在函数内部和该调用函数处*/
		switch (n) {
		case 1:CreateStrack(2); break;
		case 2:InitStrack(2); break;
		case 3:PrintStack(2); break;
		case 4:
			if (F1(count) == 0) {
				break;
			}
			printf("请输入要放入栈的元素:\n");
			int n;
			scanf("%d", &n);
			Push(2,n);
			break;
		case 5:Pop(2); break;
		case 6:GetTop(2); break;
		case 7:Delte(2); break;
		default:  printf("输入错误!\n"); break;
		}
		return;
	}
}
//判断,用在创建的函数里,判断是否二次创建
int Judge(int i) {
	if (i == 1) {
		if (s.top != -1) {	//初始的顺序栈顶为-1,如果不为说明是一个非空顺序栈
			printf("已创建过顺序栈!\n");
			return 0;
		}
	}
	if (i == 2) {
		if (l->top != NULL) {	//初始的链栈顶为NULL,如果不为说明是一个非空链栈
			printf("已创建过链栈!\n");
			return 0;
		}
	}
	return 1;
}
//判断,以count的值来判断是否创建或者初始化,防止没有创建或初始化就能进行其他操作
int F1(int count) {
	if (count == 0) {
		printf("还未创建栈!\n");
		return 0;
	}
	if (count == 1) {
		printf("该栈还未初始化!\n");
		return 0;
	}
	return 1;
}
//3.转换进制
void TransFrom(int i) {
	printf("请输入你要转换的值:\n");
	int n;
	scanf("%d", &n);
	getchar();	//接收缓冲区
	printf("请选择要转换为几进制:\na.八进制\nb.十六进制\nc.二进制\n");
	char m;
	scanf("%c", &m);
	getchar();	//接收缓冲区
	switch (m) {
	case 'a':printf("%d转换为八进制是:%o\n", n, n); return;
	case 'b':printf("%d转换为十六进制是:%x\n", n, n); return;
	case 'c':transfrom(n); return;	//调用二进制转换函数
	}
}
/*因为十进制转二进制不能直接用格式输出,所以另写一格函数*/
//十进制转换为二进制
void transfrom(int n) {	//这个n是传过来要进行转换的值
	int m = n;	//用个m代替n
	while (m > 0) {
		Push(1, m % 2);	//1代表用顺序栈的压栈方法来实现,除二求余再压栈,
		m = m / 2;
	}
	count = 2;	//因为前面设置了,不整个2代表已付初值的话,不让你压栈操作
	printf("%d转换为二进制是:\n", n);
	PrintStack(1);	//输出栈里的内容,也就是转换后的二进制数
	count = 0;	//进行完这个操作,又将count=0,方便后面进行创建站
	s.top = 0;	//因为用的是顺序栈的压栈方法,所以用完都将他回到原来的样子,不要影响后面的操作
}

//1.创建栈
void CreateStrack(int i) {
	if (i == 1) {	//创建顺序栈
		if(Judge(count)==0)	//判断是否已创建栈
			return;
		s.top = -1;	//创建栈
	}
	if (i == 2) {	//创建链栈
		if (Judge(count) == 0)	//判断是否已创建栈
			return;
		l->top = NULL;	//创建站
	}
	count=1;	//创建成功后,count变成1,说明已有栈存在
	printf("创建成功!\n");
}
//2.初始化栈
void InitStrack(int i) {
	if (count == 0) {
		printf("还未创建栈!\n");
		return;
	}
	if (count == 2) {
		printf("该栈已经初始化!\n");
		return;
	}
	printf("请输入值(以-1结束):\n");
	while (1) {
		if (i == 1) {
			/*顺序栈的栈顶指针是指向栈顶元素的上面的,所以类似下标*/
			s.top++;	//初始s.top为-1,需要先++才能赋值,因为s.top相当于数组下标
			scanf("%d", &s.data[s.top]);	//赋值
 			if (s.data[s.top] == -1) {	//以-1结束
				getchar();	//读取掉-1,避免-1被存入
				count = 2;	//初始化完成,count变为2,代表已初始化
				printf("初始化成功!\n");
				return;
			}
		}
		if (i == 2) {
			Lnode* new = (Lnode*)malloc(sizeof(Lnode));	//新建一节点
			if (new == NULL) {	//取消NULL对new的引用
				return;
			}
			scanf("%d", &new->data);	//赋值
			if (new->data == -1) {	//退出条件
				getchar();		//读取掉-1
				count = 2;	//创建完成
				printf("初始化成功!\n");
				return;
			}
			/*链栈的栈顶指针是指向栈顶那一个元素的*/
			new->next = l->top;	//类似头插法,将新的结点放在l->top的位置
			l->top= new;	//然后,栈顶指针指向这个新的值
		}
	}
}
//3.打印栈
void PrintStack(int i) {
	if (i == 1) {
		if (F1(count) == 0) {	//判断是否创建并初始化了栈
			return;
		}
		int t = s.top - 1;	//用t代替栈顶指针来进行循环,
		/*如果直接用栈顶指针的话,因为指针大小需要每次减少,
		所以等到最后就相当于将所有元素都出栈了*/
		while (t != -1) {	//-1时代表到了栈底,已经遍历了所有元素 
			printf("%d ", s.data[t]);
			t--;	//因为是栈顶指针,所以需要--
		}
	}
	if (i == 2) {
		if (F1(count) == 0) {	//判断是否创建并初始化了栈
			return;
		}
		Lnode* m= l->top;	//新建一个栈顶指针用来进行移动操作
		while (m != NULL) {	//=NULL代表遍历完
			printf("%d ", m->data);
			m = m->next;	//同链表的差不多
		}
	}
	printf("\n");	//换个行
}
//4.压栈
void Push(int i,int n) {	//i是栈的类别,n是要入栈的元素
	if (i == 1) {
		s.data[s.top] = n;	//直接将n赋给栈顶指针的位置
		s.top++;	//然后栈顶指针++依旧指向栈顶元素的上面
	}
	if (i == 2) {
		Lnode* new = (Lnode*)malloc(sizeof(Lnode));	//新建结点 
		if (new == NULL) {	//取消NULL对new的引用
			return;
		}
		new->data = n;	//将n赋给结点
		new->next = l->top;	//然后类似头插法,新节点连上top
		l->top = new;	//top在上移一个
	}
}
//5.出栈
void Pop(int i) {
	if (i == 1) {
		if (F1(count) == 0) {	//判断是否创建并初始化了栈
			return;
		}
		s.top--;	//就将栈顶指针下降一格
	}
	if (i == 2) {
		if (F1(count) == 0) {
			return;
		}
		l->top = l->top->next;	//将栈顶指针移到下一个
	}
	printf("出栈成功!\n");
}
//6.求栈顶元素
void GetTop(int i) {
	if (i == 1) {
		if (F1(count) == 0) {
			return;
		}
		printf("栈顶元素是:%d\n", s.data[s.top - 1]);	//因为顺序栈的top是栈顶元素的上面,所以要减一
	}
	if (i == 2) {
		if (F1(count) == 0) {
			return;
		}
		printf("栈顶元素是:%d\n", l->top->data);	//链栈的栈顶指针就是指向的栈顶元素
	}
}
//7.清空栈
/*就是将栈顶指针移到最下面去*/
void Delte(int i) {
	if (i == 1) {
		if (F1(count) == 0) {
			return;
		}
		s.top = -1;
	}
	if (i == 2) {
		if (F1(count) == 0) {
			return;
		}
		Lnode* n = (Lnode*)malloc(sizeof(Lnode));//这里新建一个用来方便释放空间
		n=l->top;	
		while (l->top != NULL) {
			n = n->next;	//先将n指向下一个,起到为l->top指路的作用
			free(l->top);	//然后释放空间
			l->top = n;	//然后将指针移动下一个
		}
	}
	count = 0;	//清空后,就将count=0,代表是没有栈存在的
	printf("清空完成!\n");
}

总结:

1.顺序栈的栈顶指针可以指栈顶元素也可以指栈顶元素的上一个

2.有多个scanf语句时要注意缓冲区的回车

3.十进制转八进制或十六进制可以直接通过格式输出:%x 输出十六进制,%o输出八进制

4.十进制转二进制只有用算法求出来,除二取余很适合用栈的知识

5.

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-09-14 13:36:45  更:2021-09-14 13:37:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 11:50:26-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码