数据结构(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);

目录
相关文章
|
4月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
114 1
|
20天前
|
定位技术 C语言
c语言及数据结构实现简单贪吃蛇小游戏
c语言及数据结构实现简单贪吃蛇小游戏
|
2月前
|
搜索推荐 C语言
数据结构(C语言)之对归并排序的介绍与理解
归并排序是一种基于分治策略的排序算法,通过递归将数组不断分割为子数组,直到每个子数组仅剩一个元素,再逐步合并这些有序的子数组以得到最终的有序数组。递归版本中,每次分割区间为[left, mid]和[mid+1, right],确保每两个区间内数据有序后进行合并。非递归版本则通过逐步增加gap值(初始为1),先对单个元素排序,再逐步扩大到更大的区间进行合并,直至整个数组有序。归并排序的时间复杂度为O(n*logn),空间复杂度为O(n),且具有稳定性,适用于普通排序及大文件排序场景。
|
3月前
|
存储 算法 C语言
【C语言】深入浅出:C语言链表的全面解析
链表是一种重要的基础数据结构,适用于频繁的插入和删除操作。通过本篇详细讲解了单链表、双向链表和循环链表的概念和实现,以及各类常用操作的示例代码。掌握链表的使用对于理解更复杂的数据结构和算法具有重要意义。
1005 6
|
4月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
104 1
|
4月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
381 9
|
4月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
64 1
|
2月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
158 77
|
7天前
|
算法 调度 C++
STL——栈和队列和优先队列
通过以上对栈、队列和优先队列的详细解释和示例,希望能帮助读者更好地理解和应用这些重要的数据结构。
17 4
|
20天前
|
DataX
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。

热门文章

最新文章