数据结构(c语言第2版)-----了解链表,栈,队列,串

简介: 数据结构(c语言第2版)-----了解链表,栈,队列,串

 关于链表我觉得这都是最基本的东西,但是不常见,在实际的应用中很少的使用,了解它会用就OK,不需要研究的那么深,除非做那种内存压缩,存储方面工作。



C语言中动态申请空间


  • malloc()
q=(dlink *)malloc(sizeof(dlink));


在内存空间不足或者栈满的情况下,就需要重新申请内存,此时可以使用malloc动态的申请栈,当无法知道内存具体位置的时候,想要绑定真在的存储空间,就需要用到动态的分配内存。malloc  向系统申请分配指定size个字节的内存空间。返回类型是 void* 类型。


  • realloc()
slink* p=(slink*)realloc(sizeof(slink));


先判断当前的指针是否有足够的连续空间,如果有,扩大mem_address指向的地址,并且将mem_address返回,如果空间不够,先按照newsize指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来mem_address所指内存区域(注意:原来指针是自动释放,不需要使用free),同时返回新分配的内存区域的首地址。即重新分配存储器块的地址。


了解双链表


     

双链表顾名思义就是有两个链,也就是我们之前说的指针,官方说叫前驱和后继,这样就可以前后两个方向都可以指向。也方便我们存储数据。


指针域

数据域

指针域


/*双链表*/
typedef int ElemType;
typedef struct node{
    ElemType data;
    struct node *next;     //后指针
    struct node *prior;   //前指针
}dlink;
//建立双链表
dlink *credlink(int n){
    dlink *head,*p,*s;int i;
    p=head=(dlink *)malloc(sizeof(dlink));   //创建头节点
    for(i=1;i<=n;i++){
        s==(dlink)malloc(sizeof(dlink));
        scanf("%d",&s->data);
        s->prior=p;
        p->next=s;
        p=s;
    }
    p->next=head->prior=NULL;
    return head;
}
//求表长操作
int genlen(dlink *head){
    int i=0;dlink *p;
    p=head->next;
    while(p!=NULL){
        i++;p=p->next;
    }
    return i;
}
//取元素操作                      ----和之前单链表的是一样的。
int getelem(dlink *head,int i,ElemType *e){
    int j;dlink *p;
    if(i<1)return 0;
    p=head->next;j=1;
    while(p!=NULL&&j<i){
        p=p->next;j++;    
    }
    if(p==NULL)return 0;
    *e=p->data;
    return 1;
}
//定位操作
dlink *locate(dlink *head,ElemType x){
    dlink *p;
    p=head->next;
    while(p!=NULL&&p->data!=x){
        p=p->next;    
    }
    return p;
}
//删除操作
int deletes(dlink *head,int i,ElemType *e){
    dlink *p,*q;int j;
    if(i<1)return 0;
    p=head;j=0;
    while(p->next!=NULL&&j<i-1){
        p=p->next;j++;
    }
    if(p->next==NULL)return 0;
    q=p->next;
    p->next=q->next;
    if(q->next!=NULL)q->next->prior=p;
    *e=q->data;
    free(q);
    return 1;
}
//插入操作
int insert(dlink *head,int i,ElemType x){
    dlink *p,*q;int j;
    if(i<1)return 0;
    p=head;j=0;
    while(p!=NULL&&j<i-1){
        p=p->next;j++;    
    }
    if(p==NULL)return 0;
    q=(dlink *)malloc(sizeof(dlink));
    q->data=x;
    q->next=p->next;
    q->prior=p;
    if(p->next!=NULL)p->next->prior=q;
    p->next=q;
    return 1;
}
//输出操作
void list(dlink *head){
    dlink *p;
    p=head;
    while(p->next!=NULL){
        p=p->next;
        printf("%4d",p->data);
    }
    printf("\n");
    while(p!=head){
        printf("%4d",p->data);
        p=p->prior;
    }
    printf("\n");
    while(p!=head){
        printf("%4d",p->data);
        p=p->prior;    
    }
    printf("\n");
}


了解栈


     栈是一种特殊的线性表,它只能在一段进行插入和删除操作。插入端叫栈顶,另一端叫栈低,栈的特点是先进后出,就和死胡同一样,先进去的车最后才能出来。栈的插入叫做入栈(进栈,压栈),栈的删除操作称为出栈(退栈,弹栈);含有0个元素的栈叫做空栈。


     栈是一个线性表,也具有线性表的顺序存储和链式存储两种存储结构,叫做顺序栈和链栈;根据栈的特点主要应用在语言处理和将递归算法改为非递归算法方面使用。


  • 顺序栈


/*顺序栈*/
#define INITSIZE 100      //存储空间的初始值
typedef int ElemType;    
typedef struct{                 //定义的结构体
    int top;               //表示栈顶指针
    ElemType *base;         //存放元素的动态数组空间
    int stacksize;           //当前栈的大小
}sqstack;
//初始化顺序栈
void initstack(sqstack *S){
    S->base=(ElemType *)malloc(INITSIZE *sizeof(ElemType));
    S->top=0;
    S->stacksize=INITSIZE;
}
//求栈长操作
int getlen(sqstack *S){
    return (S->top);   //直接就可以将栈顶的元素放回就OK了
}
//取栈顶元素
int gettop(sqstack *S,ElemType *e){
    if(S->top==0)return 0;
    *e=S->base[S->top-1];
    return 1;
}
//压栈操作
int push(sqstack *S,ElemType x){
    if(S->top>=S->stacksize){
        S->base=(ElemType *)realloc(S->base,(S->stacksize+1) *sizeof(ElemType));
        if(!S->base)return 0;
        S->base[S->top++]=x;
        return 1;
    }
}
//弹栈操作
int pop(sqstack *S,ElemType * e){
    if(S->top==0)return 1;
    else
        return 0;
}
//输出栈操作
void list(sqstack *S){
    int i;
    for(i=S->top-1;i>=0;i--)
        printf("%4d",S->base[i]);
    printf("\n");
}



链栈操作


/*
  链栈操作
*/
typedef int ElemType;
typedef struct node{
    ElemType data;
    struct node *next;
}linkstack;         //和单链表定义一样。
//初始化操作
linkstack *initstack(void){
    linkstack *S;
    S=(linkstack *)malloc(sizeof(linkstack));   //申请空间
    S->next=NULL;
    return S;
}
//取栈顶操作
int gettop(linkstack *S,ElemType *e){
    if(S->next==NULL)return 0;
    *e=S->next->data;
    return 1;
}
//求栈长操作
int getlen(linkstack *S){
    linkstack *p;int i;
    p=S->next;i=0;
    while(p!=NULL){
        i++;
        p=p->next;
    }
    return i;
}
//入栈操作
int push(linkstack *S,ElemType x){
    linkstack *p;
    p=(linkstack *)malloc(sizeof(linkstack));
    if(!p)return 0;   //分配有问题,就返回0;
    p->data=x;
    p->next=S->next;
    S->next=p;
    return 1;
}
//出栈操作
int pop(linkstack *S,ElemType * e){
    linkstack *p;
    if(S->next==NULL) return 0;
    p=S->next;
    *e=p->data;
    S->next=p->next;
    free(p);
    return 1;
}
//判断栈空
int emptystack(linkstack *S){
    if(S->next==NULL)
        return 1;
    else
        return 0;
}
//输出栈
void list(linkstack *S){
    linkstack *p;
    p=S->next;
    while(p!=NULL){
        printf("%4d",p->data);
        p=p->next;
    }
    printf("\n");
}


了解队列


      队列也使一种线性表,只容许在一端进行插入(队尾),另一端进行删除(队头),插入节点叫做入队,删除节点叫做出队。含有0个元素节点的队列叫做空队列。队列的特点是先进先出。


  • 循环队列
/*
  循环队列
*/
#define MAXCSIZE 100;
typedef int ElemType;
typedef struct{
    ElemType *base;
    int front;
    int rear;
}cqueue;
//初始化操作
void initqueue(cqueue *cq){
    cq->base=(ElemType *)malloc(MAXCSIZE *sizeof(ElemType));
    cq->front=cq->rear=0;
}
//求队列长操作
int getlen(cqueue *cq){
    return ((cq->rear-cq->front+MAXCSIZE)%MAXCSIZE);
}
//取对头元素操作
int getfront(cqueue *cq.ElemType *e){
    if(cq->front==cq->rear)return 0;
    *e=cq->base[cq->front];
    return 1;
}
//入队列操作
int enqueue(cqueue *cq,ElemType x){
    if((cq->rear+1)%MAXCSIZE==cq->front)return 0;
    cq->base[cq->rear]=x;
    cq->rear=(cq->rear+1)%MAXCSIZE;
    return 1;
}
//出队列操作
int outqueue(cqueue *cq,ElemType * e){
    if(cq->front==cq->rear)return 0;
    *e=cq->base[cq->front];
    cq->front=(cq->front+1)%MAXCSIZE;
    return 1;
}
//判队空操作
int emptyqueue(cqueue *cq){
    if(cq->front==cq->rear)return 11;
    else
        return 0;
}
//输出操作
void list(cqueue *cq){
    int i;
    i=cq->front;
    while(i!=cq->rear){
        printf("%4d",cq->base[i]);
        i=(i+1)%MAXCSIZE;
    }
}


链式队列

/*
 链队列
*/
typedef int ElemType;
typedef struct node{
    ElemType data;
    struct node *next;
}qlink;
typedef struct{
    qlink *front;
    qlink *rear;
}linkqueue;
//初始化操作
void initqueue(linkqueue *LQ){
    LQ->front=LQ->rear=(qlink *)malloc(sizeof(qlink));
    LQ->front->Next=NULL;
}
//求队列长度
int getlen(linkqueue *LQ){
    int i;qlink *p;
    p=LQ->front->Next;
    i=0;
    while(p!=NULL){
        i++;p=p->Next;
    }
    return i;
}
//判队空操作
int emptyqueue(linkqueue *LQ){
    if(LQ->front==LQ->rear)return 1;
    else return 0;
}
//取对头元素操作
int getfront(linkqueue *LQ,ElemType *e){
    if(LQ->front==LQ->rear)return 0;
    *e=LQ->front->Next->data;
    return 1;
}
//入队列操作
void enqueue(linkqueue *LQ,ElemType x){
    qlink *p;
    p=(qlink *)malloc(sizeof(qlink));
    p->data=x;
    p->Next=NULL;
    LQ->rear->Next=P;      //插入到队尾
    LQ->rear=P;
}
//出队列
int outqueue(linkqueue *LQ,ElemType *e){
    qlink *p;
    if(LQ->front==LQ->rear)return 0;
    p=LQ->front->Next;
    *e=p->data;
    LQ->front->Next=p->Next;
    if(LQ->rear==p)
        LQ->rear=LQ->front;
    free(p);
    return 1;
}
//输出队列操作
void list(linkqueue *LQ){
    qlink *p;
    p=LQ->front->Next;
    while(p!=NULL){
        printf("%4d",p->data);
        p=p->Next;
    }
}


了解串


      串就是我们的字符串,是一种特殊的线性表,每个表中的元素是一个字符串,即串由零个或多个字符组成的有限序列,其中双引号不是里面的内容,主要是里面包含的值。串中任意连续的字符组成的子序列称为该串的子串包含子串的串叫做主串,字符在串中的位序称为该字符在串的位置。子串在主串中的位置是以子串的第1个字符在主串中的位置来表示的。若是两个串的长度相同,且在各个位置上的字符都相同,则称这个两个串相等。



       顺序串是串的顺序存储结构,既串中的字符被依次存放在一组连续的存储单元中,一般来说一个字符占用一个字节的存储空间,因此,一个存储单元可以存储多个字符。


       串的链式存储结构称为链串,链串中的一个结点可以存储一个字符,也可以存储多个字符。链串中的每个结点所存储的字符个数称为结点大小。链串的结点大小越大,则存储密度越大,但给一些操作(插入,删除,替换等)带来了不便,可能引起大量的字符移动。结点大小越小,操作处理越方便。但存储密度会下降。<串结点大小为1>


      串的模式匹配:就是子串在主串中的定位操作。既在主串s中,从第pos个字符开始查找与子串t第1次相等的位置。若查找成功,则返回子串t的第1个字符在主串的位序。失败则返回0.



  • Brute-Force算法


基本思想:就是拿着子串在主串中挨着找,从子串的第一个开始,若和主串第一个相同则开始用子串的第二个比较主串的第二个,不同则拿着子串的第一个和主串的第二个,以此类推,主要的缺点是一些比较过的重复比较了,效率底下,目标串指针回溯消耗了大量的时间。时间复杂度:最好情况--->O(n+m),最坏情况--->O(mn);



  • KMP


思想:其实和之前的思想是一样的,只是在基础之上添加了过滤,就是没有了回溯,让比较过的不再重复比较。时间复杂度O(n+m);

目录
相关文章
|
2月前
|
存储 算法 Perl
数据结构实验之链表
本实验旨在掌握线性表中元素的前驱、后续概念及链表的建立、插入、删除等算法,并分析时间复杂度,理解链表特点。实验内容包括循环链表应用(约瑟夫回环问题)、删除单链表中重复节点及双向循环链表的设计与实现。通过编程实践,加深对链表数据结构的理解和应用能力。
63 4
|
2月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
37 1
|
8天前
|
数据库
数据结构中二叉树,哈希表,顺序表,链表的比较补充
二叉搜索树,哈希表,顺序表,链表的特点的比较
数据结构中二叉树,哈希表,顺序表,链表的比较补充
|
2月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
68 5
|
2月前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
2月前
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
60 4
|
2月前
|
算法
数据结构之购物车系统(链表和栈)
本文介绍了基于链表和栈的购物车系统的设计与实现。该系统通过命令行界面提供商品管理、购物车查看、结算等功能,支持用户便捷地管理购物清单。核心代码定义了商品、购物车商品节点和购物车的数据结构,并实现了添加、删除商品、查看购物车内容及结算等操作。算法分析显示,系统在处理小规模购物车时表现良好,但在大规模购物车操作下可能存在性能瓶颈。
53 0
|
C语言
C语言学生信息管理系统链表实现
C语言学生信息管理系统链表实现
210 0
C语言学生信息管理系统链表实现
史上最简单的C语言链表实现,没有之一
#include #include #include #define NR(x) (sizeof(x)/sizeof(x[0])) struct node { int data ; struct node *next ; }; void top_append_li...
1014 0
|
1月前
|
存储 C语言 开发者
【C语言】字符串操作函数详解
这些字符串操作函数在C语言中提供了强大的功能,帮助开发者有效地处理字符串数据。通过对每个函数的详细讲解、示例代码和表格说明,可以更好地理解如何使用这些函数进行各种字符串操作。如果在实际编程中遇到特定的字符串处理需求,可以参考这些函数和示例,灵活运用。
62 10