数据结构--线性表

来源:互联网 发布:玛雅软件培训 编辑:程序博客网 时间:2024/05/22 06:10

线性结构–线性表

数据结构中的逻辑结构分为线性结构和非线性结构,这一章和下一章我们会介绍线性结构,简单地说,线性结构是n个数据元素的有序(次序)集合,它有下列几个特征:

1.集合中必存在唯一的一个”第一个元素”;

2.集合中必存在唯一的一个”最后的元素”;

3.除最后元素之外,其它数据元素均有唯一的”后继”;

4.除第一元素之外,其它数据元素均有唯一的”前驱”。

这一章我们就来讲解线性结构中线性表,它是最常用且最简单的一种数据结构。线性表是一个含有n≥0个结点的有限序列,对于其中的结点,有且仅有一个开始结点没有前驱但有一个后继结点,有且仅有一个终端结点没有后继但有一个前驱结点,其它的结点都有且仅有一个前驱和一个后继结点。一般地,一个线性表可以表示成一个线性序列:k1,k2,…,kn,其中k1是开始结点,kn是终端结点。

一般线性表包含下列基本操作:初始化、销毁、重置为空表、判断是否为空、获取长度、根据位置获取对应元素、查找元素、获取指定元素的前驱和后继元素、插入元素、删除元素、遍历元素。

线性表的顺序实现和表示
使用数组来描述线性表的顺序存储结构

(代码中使用typedef –类型定义,详细可以看http://blog.csdn.net/mpp_king/article/details/70229150,

typedef struct{    Elemtype *elem;    //存储空间基址    int length;        //当前长度    int size;        //当前分配的表长大小}SqList;

意思就是,定义一个结构体指针,typedef是类型定义的意思。typedef struct 是为了使用这个结构体方便。
具体区别在于:
若struct node {}这样来定义结构体的话。在申请node 的变量时,需要这样写,struct node n;
若用typedef,可以这样写,typedef struct node{}NODE; 。在申请变量时就可以这样写,NODE n;
区别就在于使用时,是否可以省去struct这个关键字。

////  线性表2.c//  测试////  Created by 裴鹏 on 2017/10/25.//  Copyright © 2017年 裴鹏. All rights reserved.//#include <stdio.h>#include <stdio.h>#include <stdlib.h>#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0#define INIT_SIZE 10        //初始化表长#define INCREMENT_SIZE 5    //分配增量typedef int Status;typedef int Elemtype;/* * 存储结构 */typedef struct{    Elemtype *elem;    //存储空间基址    int length;        //当前长度    int size;        //当前分配的表长大小}SqList;/* * 初始化一个空的线性表 */Status InitList(SqList *L){    L->elem = (Elemtype *) malloc(INIT_SIZE * sizeof(Elemtype));    if (!L->elem)    {        return ERROR;    }    L->length = 0;    L->size = INIT_SIZE;    return OK;}/* * 销毁线性表 */Status DestroyList(SqList *L){    free(L->elem);    L->length = 0;    L->size = 0;    return OK;}/* * 清空线性表 */Status ClearList(SqList *L){    L->length = 0;    return OK;}/* * 判断线性表是否为空 */Status isEmpty(const SqList L){    if (0 == L.length)    {        return TRUE;    }    else    {        return FALSE;    }}/* * 获取长度 */Status getLength(const SqList L){    return L.length;}/* * 根据位置获取元素 */Status GetElem(const SqList L, int i, Elemtype *e){    if (i < 1 || i > L.length)    {        return ERROR;    }    *e = L.elem[i-1];    return OK;}/* * 比较两个元素是否相等 */Status compare(Elemtype e1, Elemtype e2){    if (e1 == e2)    {        return 0;    }    else if (e1 < e2)    {        return -1;    }    else    {        return 1;    }}/* * 查找元素 */Status FindElem(const SqList L, Elemtype e, Status (*compare)(Elemtype, Elemtype)){    int i;    for (i = 0; i < L.length; i++)    {        if (!(*compare)(L.elem[i], e))        {            return i + 1;        }    }            return ERROR;}/* * 查找前驱元素 */Status PreElem(const SqList L, Elemtype cur_e, Elemtype *pre_e){    int i;    for (i = 0; i < L.length; i++)    {        if (cur_e == L.elem[i])        {            if (i != 0)            {                *pre_e = L.elem[i - 1];            }            else            {                return ERROR;            }        }    }//这里没有必要在判断,跳出循环之后就直接return 0 就OK  //  if (i >= L.length)   //     return ;    return ERROR;}/* * 查找后继元素 */Status NextElem(const SqList L, Elemtype cur_e, Elemtype *next_e){    int i;    for (i = 0; i < L.length; i++)    {        if (cur_e == L.elem[i])        {            if (i < L.length - 1)            {                *next_e = L.elem[i + 1];                return OK;            }            else            {                return ERROR;            }        }    }        return ERROR;  }/* * 插入元素 */Status InsertElem(SqList *L, int i, Elemtype e){    Elemtype *new;    if (i < 1 || i > L->length + 1)    {        return ERROR;    }    if (L->length >= L->size)    {        new = (Elemtype*) realloc(L->elem, (L->size + INCREMENT_SIZE) * sizeof(Elemtype));        if (!new)        {            return ERROR;        }        L->elem = new;        L->size += INCREMENT_SIZE;    }    Elemtype *p = &L->elem[i - 1];    Elemtype *q = &L->elem[L->length - 1];    for (; q >= p; q--)    {        *(q + 1) = *q;    }    *p = e;    ++L->length;    return OK;}/* * 删除元素并返回其值 */Status DeleteElem(SqList *L, int i, Elemtype *e){    if (i < 1 || i > L->length)    {        return ERROR;    }    Elemtype *p = &L->elem[i - 1];    *e = *p;    for (; p < &L->elem[L->length]; p++)    {        *(p) = *(p + 1);    }    --L->length;    return OK;}/* * 访问元素 */void visit(Elemtype e){    printf("%d ", e);}/* * 遍历线性表 */Status TraverseList(const SqList L, void (*visit)(Elemtype)){    int i;    for(i = 0; i < L.length; i++)    {        visit(L.elem[i]);    }    return OK;}/* * 主函数测试 */int main(){    SqList L;    if (InitList(&L))    {        Elemtype e;        printf("init_success\n");        int i;        for (i = 0; i < 10; i++)        {            InsertElem(&L, i + 1, i);        }        printf("length is %d\n", getLength(L));        if (GetElem(L, 1, &e)) {            printf("The first element is %d\n", e);        }        else        {            printf("element is not exist\n");        }        if (isEmpty(L))        {            printf("list is empty\n");        }        else        {            printf("list is not empty\n");        }        printf("The 5 at %d\n", FindElem(L, 5, *compare));        PreElem(L, 6, &e);        printf("The 6's previous element is %d\n", e);        NextElem(L, 6, &e);        printf("The 6's next element is %d\n", e);        DeleteElem(&L, 1, &e);        printf("delete first element is %d\n", e);        printf("list:");        TraverseList(L,visit);        if (DestroyList(&L))        {            printf("\ndestroy_success\n");        }    }}

线性表的链式表示和实现

链式存储结构又一个个结点组成,每个结点包含两个域,分别是数据域,指针域
数据域:存放数据的
指针域:存放指向下一个结点的指针
这一个个结点就组成链表,也成为线性链表或者单链表,单链表最后一个结点的指针null;

除去单链表之外,还有循环链表:就是最后一个结点的指针域,指向首结点,构成一个环状的链表;

使用代码来体现单链表

#include <stdio.h>#include <stdlib.h>#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0#define OVERFLOW -2typedef int ElemType;typedef int Status;/* * 存储结构 */typedef struct LNode{    ElemType data;    struct LNode *next;}LNode, *LinkList;/* * 初始化线性表 */void InitList(LinkList *L){    *L = (LinkList) malloc(sizeof(LNode));    if (!L)    {        exit(OVERFLOW);    }    (*L)->next = NULL;}/* * 销毁线性表 */void DestroyList(LinkList *L){    LinkList temp;    while (*L)    {        temp = (*L)->next;        free(*L);        *L = temp;    }}/* * 清空线性表 */void ClearList(LinkList L){    LinkList p = L->next;    L->next = NULL;    DestroyList(&p);}/* * 判断是否为空 */Status isEmpty(LinkList L){    if (L->next)    {        return FALSE;    }    else    {        return TRUE;    }}/* * 获取长度 */int GetLength(LinkList L){    int i = 0;    LinkList p = L->next;    while (p)    {        i++;        p = p->next;    }    return i;}/* * 根据位置获取元素 */Status GetElem(LinkList L, int i, ElemType *e){    int j = 1;    LinkList p = L->next;    while (p && j < i)    {        j++;        p = p->next;    }    if (!p || j > i)    {        return ERROR;    }    *e = p->data;    return OK;}/* * 比较两个元素是否相等 */Status compare(ElemType e1, ElemType e2){    if (e1 == e2)    {        return 0;    }    else if (e1 < e2)    {        return -1;    }    else    {        return 1;    }}/* * 查找指定元素的位置 */int FindElem(LinkList L, ElemType e, Status (*compare)(ElemType, ElemType)){    int i = 0;    LinkList p = L->next;    while (p)    {        i++;        if (!compare(p->data, e))        {            return i;        }        p = p->next;    }    return 0;}/* * 获取前驱元素 */Status PreElem(LinkList L, ElemType cur_e, ElemType *pre_e){    LinkList q, p = L->next;    while (p->next)    {        q = p->next;        if (q->data == cur_e)        {            *pre_e = p->data;            return OK;        }        p = q;    }    return ERROR;}/* * 获取后继元素 */Status NextElem(LinkList L, ElemType cur_e, ElemType *next_e){    LinkList p = L->next;    while (p->next)    {        if (p->data == cur_e)        {            *next_e = p->next->data;            return OK;        }        p = p->next;    }    return ERROR;}/* * 插入元素 */Status InsertElem(LinkList L, int i, ElemType e){    int j = 0;    LinkList s, p = L;    while (p && j < i - 1)    {        j++;        p = p->next;    }    if (!p || j > i - 1)    {        return ERROR;    }    s = (LinkList) malloc(sizeof(LNode));    s->data = e;    s->next = p->next;    p->next = s;    return OK;}/* * 删除元素并返回值 */Status DeleteElem(LinkList L, int i, ElemType *e){    int j = 0;    LinkList q, p = L;    while (p->next && j < i - 1)    {        j++;        p = p->next;    }    if (!p->next || j > i - 1)    {        return ERROR;    }    q = p->next;    p->next = q->next;    *e = q->data;    free(q);    return OK;}/* * 访问元素 */void visit(ElemType e){    printf("%d ", e);}/* * 遍历线性表 */void TraverseList(LinkList L, void (*visit)(ElemType)){    LinkList p = L->next;    while (p)    {        visit(p->data);        p = p->next;    }}int main(){    LinkList L;    InitList(&L);    ElemType e;    int i;    if (L)    {        printf("init success\n");    }    if (isEmpty(L))    {        printf("list is empty\n");        }    for (i = 0; i < 10; i++)    {        InsertElem(L, i + 1, i);    }    if (GetElem(L, 1, &e)) {        printf("The first element is %d\n", e);    }    printf("length is %d\n", GetLength(L));    printf("The 5 at %d\n", FindElem(L, 5, *compare));    PreElem(L, 6, &e);    printf("The 6's previous element is %d\n", e);    NextElem(L, 6, &e);    printf("The 6's next element is %d\n", e);    DeleteElem(L, 1, &e);    printf("delete first element is %d\n", e);    printf("list:");    TraverseList(L,visit);    DestroyList(&L);    if (!L) {        printf("\ndestroy success\n");        }}

栈和队列也属于线性表,不过是功能受限制
首先我们来讲讲栈,栈是只能在表尾进行插入或删除操作的线性表,通常我们称表尾端为栈顶,表头端为栈底,它是一种先进后出的线性表,既只能在表尾端插入元素,称为入栈,也只能在表尾端删除元素,称为退栈,如下图所示

栈既然也是线性表,那么它也有顺序存储结构和链式存储结构两种表示方法,这两种表示方法实现类似,我们这里讲解一下顺序存储结构的代码实现:

#include <stdio.h>#include <stdlib.h>#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0#define OVERFLOW -2#define INIT_SIZE 20#define INCREMENT_SIZE 5typedef int SElemType;typedef int Status;/* * 存储结构 */typedef struct{    SElemType *base;    //栈尾指针    SElemType *top;        //栈顶指针    int size;            //栈的大小}SqStack;/* * 初始化栈 */Status InitStack(SqStack *S){    S->base = (SElemType*) malloc(INIT_SIZE * sizeof(SElemType));    if (!S->base)    {        exit(OVERFLOW);    }    S->top = S->base;    S->size = INIT_SIZE;    return OK;}/* * 销毁栈 */Status DestroyStack(SqStack *S){    free(S->base);    S->base = NULL;    S->top = NULL;    S->size = 0;    return OK;}/* * 清空栈 */Status ClearStack(SqStack *S){    S->top = S->base;    return OK;}/* * 判断栈是否为空 */Status IsEmpty(SqStack S){    if (S.top == S.base)    {        return TRUE;    }    else        return FALSE;}/* * 获取栈的长度 */int GetLength(SqStack S){    return S.top - S.base;}/* * 获取栈顶元素 */Status GetTop(SqStack S, SElemType *e){    if (S.top > S.base)    {        *e = *(--S.top);        return OK;    }    else    {        return ERROR;    }}/* * 压栈 */Status Push(SqStack *S, SElemType e){    if ((S->top - S->base) / sizeof(SElemType) >= S->size)    {        S->base = (SElemType*) realloc(S->base, (S->size + INCREMENT_SIZE) * sizeof(SElemType));        if (!S->base)        {            exit(OVERFLOW);        }        S->top = S->base + S->size;        S->size += INCREMENT_SIZE;    }    *S->top = e;    S->top++;    return OK;}/* * 退栈 */Status Pop(SqStack *S, SElemType *e){    if (S->top == S->base)    {        return ERROR;    }    S->top--;    *e = *S->top;    return OK;}/* * 访问元素 */void visit(SElemType e){    printf("%d ", e);}/* * 遍历栈 */Status TraverseStack(SqStack S, void (*visit)(SElemType)){    while (S.top > S.base)    {        visit(*S.base);        S.base++;    }    return OK;}int main(){    SqStack S;    if (InitStack(&S))    {        SElemType e;        int i;        printf("init_success\n");        if (IsEmpty(S))        {            printf("Stack is empty\n");        }        for (i = 0; i < 10; i++)        {            Push(&S, i);        }        GetTop(S, &e);        printf("The first element is %d\n", e);        printf("length is %d\n", GetLength(S));        Pop(&S, &e);        printf("Pop element is %d\n", e);        TraverseStack(S, *visit);        if (DestroyStack(&S))        {            printf("\ndestroy_success\n");        }    }}

通过栈可以解决很多问题,例如数值转换、括号匹配、迷宫求解、表达式求值和汉诺塔等等问题。