0
点赞
收藏
分享

微信扫一扫

数据结构DAY4--哈希表

秦瑟读书 04-13 11:30 阅读 1

1.3栈

1.概念:
只能在一端进行插入和删除操作的线性表,进行插入和删除的一端叫做栈顶,另一端叫做栈底
2. 特点:
先入后出,后入先出
FILO,LIFO
1.3.1顺序栈:seqstack
sequence 顺序 stack 栈
1)逻辑结构:线性结构
2)存储结构:顺序存储
3)操作:
//1.创建一个空的栈
//2.入栈
//3.判断栈是否为满
//4.出栈
//5.判断栈是否为空
//6.求栈的长度
//7.获取栈顶数据

#ifndef _SEQSTACK_H_
#define _SEQSTACK_H_

typedef struct seqstack
{
    int* data;//指向栈的存储位置
    int maxlen;//保存栈的最大长度
    int top;//称为栈针,用的时候,心里面可以将按照顺序表里的last来使用
    //top 始终代表当前栈内最后一个有效元素的下标
}seqstack_t;
//1.创建一个空的栈
seqstack_t *CreateEpSeqStack(int len);//len代表的是创建栈的时候的最大长度
//2.判断是否为满,满返回1 未满返回0
int	 IsFullSeqStack(seqstack_t *p);
//3.入栈 
int  PushStack(seqstack_t *p, int data);//data代表入栈的数据
//4.判断栈是否为空
int IsEpSeqStack(seqstack_t *p);
//5.出栈 
int PopSeqStack(seqstack_t *p);
//6. 清空栈 
void ClearSeqStack(seqstack_t *p);
//7. 获取栈顶数据(注意不是出栈操作,如果出栈,相当于删除了栈顶数据,只是将栈顶的数据获取到,不需要移动栈针)
int GetTopSeqStack(seqstack_t *p);
//8. 求栈的长度
int LengthSeqStack(seqstack_t *p);
#endif

具体实现

#include"seqstack.h"
//1.创建空栈
seqstack_t *CreateEpSeqStack(int len)
{
    seqstack_t *p=(seqstack_t *)malloc(sizeof(seqstack_t));
    if(p==NULL)
    {
        perror("struct malloc err");
        return NULL;
    }
    p->maxlen=len;
    p->top=-1;
    p->data=(int *)malloc(sizeof(int)*p->maxlen);
    if(p->data==NULL)
    {
        perror("stack malloc err");
        return NULL;
    }
    return p;
}
//2.判满
int IsFullSeqStack(seqstack_t *p)
{
return p->top+1 == p->maxlen;
}
//3.入栈
int PushStack(seqstack_t *p,int num)
{
    if(IsFullSeqStack(p))
    {
        perror("stack full");
        return -1;
    }//1.容错判满
    p->top++;//2.移动栈针
    p->data[p->top]=num;//3.入栈
    return 0;
}
//4.判空
int IsEqSeqStack(seqstack_t *p)
{
return p->top == -1;
}
//5.出栈
int PopStack(seqstack_t *p)
{
    if(IsEqSeqStack(p))
    {
        perror("stack empty");
        return -1;
    }//容错判空
    int data=p->data[p->top];
    p->top--;
    return data;
}
//6.清空栈
void ClearSeqStack(seqstack_t *p)
{
    p->top=-1;
}
//7.获取栈顶元素
int GetTopSeqStack(seqstack_t *p)
{
if(IsEqSeqStack(p))
{
    perror("stack empty");
    return -1;
}
    return p->data[p->top];
}
//8.求栈长度
int LengthSeqStack(seqstack_t *p)
{
    return p->top+1;
}

1.3.2链式栈
1)逻辑结构:线性结构
2)存储结构:链式存储

#ifndef _LINKSTACK_H_
#define _LINKSTACK_H_
#include <stdio.h>
#include <stdlib.h>
//入栈和出栈只在第一个节点位置操作
typedef int datatype;
typedef struct linkstack
{
    datatype data;//数据域
    struct linkstack *next;//指针域
}linkstack_t;
//1.创建一个空的栈
void CreateEpLinkStack(linkstack_t **ptop);
//2.入栈   data是入栈的数据
参数上之所以采用二级指针,因为我们要随着入栈添加新的节点作为头,top需要永远指向当前链表的头,
那么修改main函数中的top,我们采用地址传递
int PushLinkStack(linkstack_t **ptop, datatype data);
//3.判断栈是否为空
int IsEpLinkStack(linkstack_t *top);
//4.出栈
datatype PopLinkStack(linkstack_t **ptop);
//5.清空栈
void ClearLinkStack(linkstack_t **ptop);//用二级指针,是因为清空后需要将main函数中的top变为NULL
//6.求栈的长度
int LengthLinkStack(linkstack_t *top);//用一级指针,是因为我只是求长度,不需要修改main函数中top指针的指向
//7.获取栈顶数据,不是出栈,不需要移动main函数中的top,所以用一级指针
datatype GetTopLinkStack(linkstack_t *top);
#endif

#include"linkstack.h"
//1.创建一个空的栈
void CreateEpLinkStack(linkstack_t **ptop)
{
    *ptop=NULL;
}
//2.入栈   data是入栈的数据
// 参数上之所以采用二级指针,因为我们要随着入栈添加新的节点作为头,top需要永远指向当前链表的头,
// 那么修改main函数中的top,我们采用地址传递
int PushLinkStack(linkstack_t **ptop, datatype data)
{
    //1.开辟节点
    linkstack_t *pnew=(linkstack_t *)malloc(sizeof(linkstack_t));
    if(pnew==NULL)
    {
        perror("pnew err");
        return -1;
    }
    pnew->data=data;
    pnew->next=*ptop;//2.新节点插入当前无头链表,作为头节点
    *ptop=pnew;//3.移动栈针,栈针永远指向头节点
    return 0;
}
//3.判断栈是否为空
int IsEpLinkStack(linkstack_t *top)
{
    return top==NULL;
}
//4.出栈
datatype PopLinkStack(linkstack_t ** ptop)
{
    if(IsEpLinkStack(*ptop))
    {
        perror("linkstack empty");
        return -1;
    }
    //定义一个指针pdel用于删除节点
    linkstack_t *pdel=*ptop;
    datatype data=pdel->data;//临时变量存储被删除数据
    *ptop=pdel->next;//跨过被删除节点
    free(pdel);//释放被删除节点
    pdel=NULL;
    return data;
}
//5.清空栈
void ClearLinkStack(linkstack_t **ptop)//用二级指针,是因为清空后需要将main函数中的top变为NULL
{
    linkstack_t *pdel;
    while(*ptop!=NULL)
    {   
        pdel=*ptop;
        *ptop=pdel->next;
        free(pdel);
        pdel=NULL;
    }
}
//6.求栈的长度
int LengthLinkStack(linkstack_t *top)
{
    int sum=0;
    while(top!=NULL)
    {
        sum++;
        top=top->next;
    }
    return sum;
}//用一级指针,是因为我只是求长度,不需要修改main函数中top指针的指向
//7.获取栈顶数据,不是出栈,不需要移动main函数中的top,所以用一级指针
datatype GetTopLinkStack(linkstack_t *top)
{
    if(IsEpLinkStack(top))
    {
        perror("stack empty");
        return -1;
    }
    return top->data;
}

总结:
顺序栈和链式栈的区别?
1)存储结构不同,顺序栈相当于数组,连续;链式栈 链表 内存不连续
2)顺序栈长度受限制,链式栈不会

如何避免头文件重复包含

防止结构体等重新定义

#ifndef    _xxx_H_
#define	_xxx_H_
....
#endif

顺序表和链表的相同点和不同点有哪些?
相同点: 都是线性表 逻辑结构:线性结构 一对一
不同点:
(1)顺序表存储结构是顺序存储,内存当中存储不连续的链表是链式存储,通过指针将节点联系到一起,内存上存储不连续
(2)顺序表(数组)长度固定,链表不固定
(3)顺序表查找方便,但是插入和删除麻烦,链表插入和删除方便,但是查找麻烦
线性表的特征?
线性表: 顺序表 链表 栈(顺序栈和链式栈) 队列(顺序队列也叫循环队列和链式队列)
线性表的特征:一对一,每个节点最多有一个前驱和一个后继(首尾节点除外)

1.4队列(queue)

顺序队列(循环队列)和链式队列

  1. 概念:
    只允许在两端进行插入和删除操作的线性表,在队尾插入,在队头删除
  2. 特点:
    先入先出,后入后出
    FIFO LILO
    1.4.1顺序队列
    1)逻辑结构:线性结构
    2)存储结构:顺序存储
    3)操作

1.4.1循环队列

#include <stdio.h>
#include <stdlib.h>
#define N 5
typedef int datatype;
typedef struct
{
    datatype data[N];//循环队列的数组
    int rear;//存数据端 rear 后面
    int front;//取数据端 front 前面
}sequeue_t;
//1.创建一个空的队列
sequeue_t *CreateEmptySequeue();
//2.入列 data代表入列的数据
int InSequeue(sequeue_t *p,datatype data);
//3.判断队列是否为满
int IsFullSequeue(sequeue_t *p);
//4.判断队列是否为空
int IsEmptySequeue(sequeue_t *p);
//5.出列 
datatype OutSequeue(sequeue_t *p);
//6.求队列的长度
int LengthSequeue(sequeue_t *p);
//7.清空队列函数
void ClearSequeue(sequeue_t *p);

具体实现

#include"sequeue.h"

//1.创建一个空的队列
sequeue_t *CreateEmptySequeue()
{
    sequeue_t *p=(sequeue_t *)malloc(sizeof(sequeue_t));
    if(p==NULL)
    {
        perror("p error");
        return NULL;
    }
    p->front=0;
    p->rear=0;
    return p;
}
//2.判断队列是否为满
int IsFullSequeue(sequeue_t *p)
{
    return (p->rear+1)%N == p->front;
}
//3.入列 data代表入列的数据 浪费了一个存储空间
int InSequeue(sequeue_t *p,datatype data)
{
    //1.判满
    if(IsFullSequeue(p))
    {
        perror("queue full");
        return -1;
    }
    //2.入队
    p->data[p->rear]=data;
    //3.尾指针后移
    p->rear=(p->rear+1)%N;
    return 0;
}
//4.判断队列是否为空
int IsEmptySequeue(sequeue_t *p)
{
    return p->front == p->rear;
}
//5.出列 
datatype OutSequeue(sequeue_t *p)
{//1.判空
    if(IsEmptySequeue(p))
    {
        perror("queue empty");
        return -1;
    }
    //2.取出数据
    datatype data=p->data[p->front];
    //3.移动对头
    p->front=(p->front+1) % N;
    return data;
}
//6.求队列的长度
int LengthSequeue(sequeue_t *p)
{
    return (p->rear + N - p->front) % N;
}
//7.清空队列函数
void ClearSequeue(sequeue_t *p)
{
    p->rear = p->front;
}

循环队列中,假设数组的元素个数为N,那么循环队列中存储最多的数据个数为N-1个
因为需要一个空间判断是否队列为满

1.4.2链式队列

#include <stdio.h>
#include <stdlib.h>
typedef int datatype;
typedef struct node
{
    datatype data;//数据域
    struct node *next;//指针域
}linkqueue_node_t,*linkqueue_list_t;

//linkqueue_list_t p === linkqueue_node_t *
typedef struct//将队列头指针和尾指针封装到一个结构体里
{
    linkqueue_list_t front;//相当于队列的头指针
    linkqueue_list_t rear;//相当于队列的尾指针
    //有了链表的头指针和尾指针,那么我们就可以操作这个链表
}linkqueue_t;
//1.创建一个空的队列
linkqueue_t *CreateEmptyLinkQueue();
//2.入列 data代表入列的数据
int InLinkQueue(linkqueue_t *p,datatype data);
//3.出列 
datatype OutLinkQueue(linkqueue_t *p);
//4.判断队列是否为空
int IsEmptyLinkQueue(linkqueue_t *p);
//5.求队列长度的函数
int LengthLinkQueue(linkqueue_t *p);
//6.清空队列
void ClearLinkQueue(linkqueue_t *p);

具体实现

#include "linkqueue.h"

//1.创建一个空的队列
linkqueue_t *CreateEmptyLinkQueue()
{
    //1.开辟存放头尾指针的结构体大小空间
    linkqueue_t *p=(linkqueue_t *)malloc(sizeof(linkqueue_t));
    if(p==NULL)
    {
        perror("p err");
        return NULL;
    }//初始化头尾指针,指向头节点
   p->rear=p->front=(linkqueue_list_t)malloc(sizeof(linkqueue_node_t));
    if(p->rear==NULL)
    {
        perror("p->front malloc err");
        return NULL;
    }
    //头节点初始化
    p->front->next=NULL;
    return p;
}
//2.入列 data代表入列的数据
int InLinkQueue(linkqueue_t *p,datatype data)
{
    linkqueue_list_t pnew=(linkqueue_list_t)malloc(sizeof(linkqueue_node_t));
    if(pnew==NULL)
    {
        perror("pnew err");
        return -1;
    }
    //初始化节点
    pnew->data=data;
    pnew->next=NULL;
     //插入队列 移动尾指针
    p->rear->next=pnew;
    p->rear=pnew;
    return 0;
}
//3.判断队列是否为空
int IsEmptyLinkQueue(linkqueue_t *p)
{
    return p->rear==p->front;
}
//4.出列 
datatype OutLinkQueue(linkqueue_t *p)
{
    if(IsEmptyLinkQueue(p))
    {
        perror("queue empty");
        return -1;
    }
    linkqueue_list_t pdel;
    pdel=p->front;
    p->front=p->front->next;
    free(pdel);
    pdel=NULL;
    return p->front->data;
}
//5.求队列长度的函数
int LengthLinkQueue(linkqueue_t *p)
{
    int len=0;
    linkqueue_list_t flag=p->front;
    while(flag->next!=NULL)
    {
        flag=flag->next;
        len++;
    }
    return len;
}
//6.清空队列
void ClearLinkQueue(linkqueue_t *p)
{
    while(p->front->next!=NULL)
    {
       OutLinkQueue(p);
    }

}
举报

相关推荐

0 条评论