数据结构--线性表

线性结构–线性表

数据结构中的逻辑结构分为线性结构和非线性结构,这一章和下一章我们会介绍线性结构,简单地说,线性结构是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 -2

typedef 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 5

typedef 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");
        }
    }
}

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值