//
// Created by lijing on 23-12-6.
//
#include "../Define.h"
#define MAX 1024
//栈的顺序存储:利用数组模拟出先进后出的数据结构
//将栈的定义放在头文件里,这样就可以在多个文件中使用,并标上#pragma once
//#pragma once是一个比较常用的C/C++预处理指令,只要在头文件的最开始加入这条预处理指令,就能够保证头文件只被编译一次
//#pragma once好处是方式一由语言支持所以移植性好,方式二 可以避免名字冲突,方式三可以防止头文件被重复引用(也可以是不好)
struct SStack{
void * data[MAX];
int m_Size;
};
//为了不随便获取到SStack里边的数据,给用户使用就用void * 指针取栈的地址
typedef void * SeqStack;
//初始化栈
SeqStack initSeqStack(){
// struct SStack * myStack = new SStack();//分配内存的两种方式,new和malloc
//struct SStack * myStack = malloc(sizeof(SStack));//会报错,需要强转
struct SStack * myStack = (struct SStack *)malloc(sizeof(SStack));
if (myStack == NULL){
return NULL;
}
//初始化数组:将数组的每个元素都置为0(也可以使用for循环)
// 长度是MAX,每个数据都是void * 类型,所以是sizeof(void *),再乘上MAX
memset(myStack->data, 0, sizeof(void *) * MAX);
//初始化大小为0
myStack->m_Size = 0;
return myStack;
};
//入栈
void pushSeqStack(SeqStack stack, void * data){
//入栈的本质是数组尾插
if (stack == NULL){
return;
}
if (data==NULL){
return;
}
//如果栈满了,就不能再入栈了
struct SStack * myStack = (struct SStack *)stack;//强转拿到真实的栈
if (myStack->m_Size >= MAX){
return;
}
//尾插:尾部数据等于用户传入的数据,然后尾部+1
myStack->data[myStack->m_Size] = data;
myStack->m_Size++;
};
//出栈
void popSeqStack(SeqStack stack){
//出栈的本质是数组w尾删
if (stack== NULL){
return;
}
//还原为真实的栈
struct SStack * myStack = (struct SStack *)stack;
//如果栈为空,就不能再出栈了
if (myStack->m_Size == 0){
return;
}
//尾删:然后尾部-1,尾指针空
myStack->data[myStack->m_Size-1] = NULL;
myStack->m_Size--;
};
//返回栈顶:
void * topSeqStack(SeqStack stack){
//使用*topSeqStack,返回的是void * 指针
//因为栈里存的是void * 指针,表示可以存任意类型的数据
if (stack == NULL){
return NULL;
}
//还原为真实的栈
struct SStack * myStack = (struct SStack *)stack;
//如果栈为空,就不能再出栈了,返回NULL
if (myStack->m_Size == 0){
return NULL;
}
return myStack->data[myStack->m_Size-1];
};
//获取栈的大小
int sizeSeqStack(SeqStack stack){
if (stack == NULL){
return 0;
}
struct SStack * myStack = (struct SStack *)stack;
return myStack->m_Size;
};
//判断栈是否为空
int isEmptySeqStack(SeqStack stack){
if (stack == NULL){
return -1;//返回-1,表示栈为空,非0是真
}
struct SStack * myStack = (struct SStack *)stack;
if (myStack->m_Size == 0){
return 1;//返回0,表示栈为空,1是真
}
return 0;//返回1,表示栈不为空
};
//销毁栈
void destructSeqStack(SeqStack stack){
if (stack == NULL){
return;
}
free(stack);
//free后置空,防止野指针?
stack = NULL;
};
struct Person{
char name[10];
int age;
};
void test(){
SeqStack stack = initSeqStack();
//创建数据
struct Person p1={"aaa",12};
struct Person p2={"bbb",13};
struct Person p3={"ccc",14};
struct Person p4={"ddd",15};
struct Person p5={"eee",16};
//入栈
pushSeqStack(stack, &p1);
pushSeqStack(stack, &p2);
pushSeqStack(stack, &p3);
pushSeqStack(stack, &p4);
pushSeqStack(stack, &p5);
printf("入栈后栈的元素个数为:%d\n",sizeSeqStack(stack));
//通过循环访问栈,栈不为空,就出栈
while (isEmptySeqStack(stack)==0){
//出栈:topSeqStack(stack)返回的是void * 指针
//因为栈里存的是void * 指针,表示可以存任意类型的数据
//强转成struct Person * 指针???为什么类型一样还要强转?
struct Person * p = (struct Person *)topSeqStack(stack);
printf("%s %d\n",p->name, p->age);
popSeqStack(stack);
}
printf("出栈后栈的元素个数为:%d\n",sizeSeqStack(stack));
//销毁栈
destructSeqStack(stack);
}
int main(){
test();
}
/SunxuStack
入栈后栈的元素个数为:5
eee 16
ddd 15
ccc 14
bbb 13
aaa 12
出栈后栈的元素个数为:0
Process finished with exit code 0
线性表的顺序存储
//#include "SunxuLinear.h"
#include "../Define.h"
//---------------顺序线性表------------
//Status是函数返回值类型,其值是函数结果状态代码。
typedef int Status;
typedef int ElemType;
typedef struct{
ElemType *elem;//ElemType为数据元素类型。elem是指针,用于存储动态分配数组的内存基址
int length; //表长
int listsize; //容量,以sizeof(ElemType)为单位
}SqList; //sequential list
//构造一个空的顺序表
Status InitList(SqList &L){
// 为顺序表分配初始内存空间
L.elem = (ElemType*) malloc (
LIST_INIT_SIZE * sizeof (ElemType));
// 分配失败
if (!L.elem) exit(OVERFLOW);
// 初始化顺序表
L.length = 0;
// 初始化顺序表大小=顺序表的最大容量
L.listsize = LIST_INIT_SIZE;
// 返回状态码OK,表示初始化成功
return OK; //OK是1
}
Status ListInsert_Sq(SqList &L, int i, ElemType e) {
if (i < 1 || i > L.length + 1) return ERROR; //不合法
if (L.length == L.listsize) { //存储空间已满,增加分配
ElemType *newbase =
(ElemType *) realloc(L.elem, (L.listsize + LISTINCREMENT) * sizeof(ElemType));
if (!newbase) exit(OVERFLOW); //存储分配失败
L.elem = newbase; //更新指针=新分配的存储空间的首地址
L.listsize += LISTINCREMENT; // 增加存储容量
}
ElemType *q=L.elem+i-1;//q为插入位置的前一个位置
//插入位置之后的元素向后移动
for(ElemType *p = L.elem+L.length-1; p>=q;--p)
//p为插入位置之后的元素,p-1为插入位置之前的元素
//p-1为插入位置之前的元素,*(p+1)为插入位置之后的元素
*(p+1)=*p;
//插入元素
*q = e;
//表长加1
++L.length;
return OK;
}
Status ListDelete(SqList &L,int i, ElemType &e){
if ((i < 1) || (i > L.length)) return ERROR; // 删除位置不合法,包括空表的情况
ElemType *p = L.elem + i-1; //p为被删除元素的位置
e = *p; // 被删除元素L.elem[i-1]赋给 e
ElemType *q=L.elem+L.length-1; //q为最后一个元素的位置
for(++p;p<=q;++p) *(p-1)=*p;//p为被删除元素之后的元素,*(p-1)为被删除元素之前的元素
--L.length;
return OK;
}
int LocateElem(SqList L, ElemType e) {
//在顺序表中查询数据元素e是否存在,返回它的位序
int i = 1;
// 从首元素开始比较
ElemType * p = L.elem; //p是指针,指向首元素
while ((i <= L.length) && (e != *p))
{ ++i; ++p; } //继续查找
if (i <= L.length) return i; //查找成功,返回位序
else return 0; //不成功
}
void ListTraverse(SqList L){
printf("一共有'%d'个元素。\n",L.length);
for (int i=1; i<= L.length ;i++)
printf("第'%d'个元素是'%d'\n",i,L.elem[i-1]);
}
int main() {
SqList L;
ElemType e;
int i;
//建表
InitList(L);
//插入5
e=10;
for (int i = 1; i < 5; i++) {
printf("请输入插入元素的值");
cin>>e;
ListInsert_Sq(L, i, e); //在表L中的第i个位置插入e
}
printf("表的长度为:'%d'\n",L.length);
ListTraverse(L);
//删除
printf("请输入要删除的表中元素位置:");
cin>>i;
ListDelete(L,i,e);
cout<<"表的最新的长度是:"<<endl;
cout<<L.length<<endl;
ListTraverse(L); //遍历链表的数据元素
}
线性表的链式存储
#include "../Define.h"
//线性表的链式存储结构
typedef int ElemType;
typedef int Status;
typedef struct LNode { //定义链表结点类型
ElemType data;// 数据域无*
struct LNode *next;// 指针域
}LNode, *LinkList;
LinkList L;
void ListTraverse(LinkList L) {
cout<<"遍历链表:\n";
LNode *p=L->next; //p从第一个数据结点(首元结点)开始
// cout<<"输出数据元素的值:\n";
while (p){
cout<<p->data;
cout<<"\n";
p=p->next;//修改指针
}
}
//前插法创建结点
void CreateList(LinkList &L, int n){
//生成含n个数据元素的链表
//逆序输入n个数据元素,建立带头结点的单链表L
L=new LNode;
// L = (LinkList) malloc (sizeof (LNode));//或者L=new LNode分配内存空间
L->next = NULL;
for (int i = n; i > 0; --i) { //for (i=1;i<=n;++i)
// LNode *s;
LNode * s = static_cast<LNode *>(malloc(sizeof(LNode)));
cin>>s->data; //输入元素值
s->next = L->next;
L->next = s;//插入为首元结点
}
}
//还有后插法插入结点
void CreateList_R(LinkList &L,int n)
{//正位序输入n个元素的值,建立带表头结点的单链表L
L=new LNode;
L->next=NULL; //先建立一个带头结点的空链表
int i;
LinkList r=L; //尾指针r指向头结点
for(i=0;i<n;++i)
{
LNode *p=new LNode; //生成新结点
cin>>p->data; //输入元素值赋给新结点*p的数据域
p->next=NULL; r->next=p; //将新结点*p插入尾结点*r之后
r=p; //r指向新的尾结点*p
}
}
Status ListInsert(LinkList &L, int i, ElemType e ){
/*在带头结点的单链表L中第i 个结点之前插入新元素 e. */
LinkList p=L;
int j=0;//计数器
while (p && j < i-1){//顺链域向后扫描,直到p为空或p指向第i个元素
p = p->next;
j++;
}
if (!p || j>i-1) return ERROR;
LNode *s=new LNode ;
s->data = e;
s->next = p->next;
p->next = s;
return OK;
}
Status ListDelete(LinkList &L, int i, ElemType &e)
{ //删除带头结点的单链表L中的第 i 个结点
LNode *p = L;//定义指向头结点即链表的指针
int j = 0;
while (p->next && j < i-1){//顺链域向后扫描,直到p为空或p指向第i个元素
p = p->next;
++j;
} // 查找第 i-1 个结点
if (!(p->next) || j > i-1) return ERROR;// 删除位置不合理
LNode *q = p->next;//q指向第i个结点
p->next = q->next; //删除并释放结点
e = q->data; delete q;
return OK;
}
Status GetElem(LinkList L,int i,ElemType &e)
{//在带头结点的单链表L中根据序号i获取元素的值,用e返回L中第i个数据元素的值
LNode *p = L;
p=L->next;
int j=1; //初始化,p指向首元结点,计数器j初值赋为1
while(p&&j<i) //顺链域向后扫描,直到p为空或p指向第i个元素
{
p=p->next; //p指向下一个结点
++j; //计数器j相应加1
}
if(!p||j>i)return ERROR; //i值不合法i>n或i≤0
e=p->data; //取第i个结点的数据域
return OK;
}
int main(){
LinkList L;// L 为头指针。等价于LNode *L。LinkList L提高可读性
cout<<"请逆序输入链表的5个元素:";
CreateList(L, 5) ; //逆序输入5个数据元素,创建链表;
ListTraverse(L);
int i = 4;
ElemType e=10000;
cout<<"在第4位处先插入元素e:\n";
ListInsert( L, i, e );
ListTraverse(L);
cout<<"取第N个元素?";
int a;
cin>>a;
GetElem(L,a,e);
printf("%d\n",e);
cout<<"再删除第4个元素:";
ListDelete(L, i, e);
ListTraverse(L);
cout<<"取第N个元素?";
cin>>a;
GetElem(L,a,e);
printf("%d",e);
}
循环队列
#include "../Define.h"
#define MAXQSIZE 10 //队列的最大长度
typedef int QElemType; //队列元素为整数类型
//循环队列的类型定义
//typedef struct QNode{
// QElemType data;
// struct QNode *next;
//}QNode,*QueuePtr;
typedef struct{ // 链队列类型
QElemType *base;//存储空间基址
int front; // 队头指针
int rear; // 队尾指针
// QNode front;
// QNode rear;
}SqQueue;
//注意类型符合,对头队尾指针跟QElemType一样都是int ,后面才可以加减?
//队列的基本操作实现
//构造一个空队列Q
Status InitQueue(SqQueue &Q){
Q.base = new int[MAXQSIZE];
//或者Q.base = (ElemType *) malloc(MAXQSIZE *sizeof (ElemType));
if(!Q.base) exit(OVERFLOW);
Q.front = Q.rear = 0;
return OK;
}
// 插入元素e为Q的新的队尾元素
Status EnQueue(SqQueue &Q, QElemType e) {
if( (Q.rear + 1) % MAXQSIZE == Q.front) {
cout<<"队列满";
return ERROR ;
}
Q.base[Q.rear] = e;// 插入元素e
// *(Q.base + Q.rear)=e;
Q.rear = (Q.rear+1) % MAXQSIZE;//移动队尾指针Q.rear到下一个位置
return OK;
}
// 删除元素队头元素,存为e
Status DeQueue(SqQueue &Q, QElemType &e) {
if (Q.front == Q.rear){
cout<<"队列空";
return ERROR;
}
e=Q.front; // 删除元素队头元素,存为e
Q.front = (Q.front + 1) %MAXQSIZE;// 移动队头指针Q.front到下一个位置
return OK;
}
//判断队列是否为空
Status QueueEmpty(SqQueue Q){
return (Q.front == Q.rear);
}
//求循环队列的长度
Status QueueLength(SqQueue Q){
return (Q.rear-Q.front+MAXQSIZE) % MAXQSIZE;
}
//遍历循环队列
void QueueTraverse(SqQueue Q){
int i,k;
k=QueueLength(Q);
for(i=1;i<=k;i++){
printf("%d ",Q.base[Q.front]);
Q.front=(Q.front+1)%MAXQSIZE;
}
printf("\n");
}
int main() {
int n, e, i;
SqQueue Q;
InitQueue(Q); //初始化循环队列
printf("该循环队列最多可存放%d个元素\n", MAXQSIZE - 1);
printf("请输入数据元素的个数n \n");
scanf("%d", &n);
printf("\n请输入%d个整数\n", n);
for (i = 1; i <= n; i++) {
scanf("%d", &e);
EnQueue(Q, e); //入队
}
printf("Q=");
QueueTraverse(Q); //输出循环队列q
printf("\n请输入入队元素e\n");
scanf("%d", &e);
EnQueue(Q, e); //入队
printf("Q=");
QueueTraverse(Q); //输出插入后的循环队列
printf("\n执行出队操作\n");
DeQueue(Q, e); //出队
printf("出队元素是下标%d\n", e);//输出出队元素值
printf("Q=");
QueueTraverse(Q); //输出删除后的循环队列
}
结果
/CircleQueue
该循环队列最多可存放9个元素
请输入数据元素的个数n
3
请输入3个整数
1 2 5
Q=1 2 5
请输入入队元素e
3
Q=1 2 5 3
执行出队操作
出队元素是下标0
Q=2 5 3
Process finished with exit code 0