栈&&循环队列&&线性表的顺序和链式存储

//
// 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

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值