数据结构--线性表
来源:互联网 发布:玛雅软件培训 编辑:程序博客网 时间: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"); } }}
通过栈可以解决很多问题,例如数值转换、括号匹配、迷宫求解、表达式求值和汉诺塔等等问题。
- 数据结构拾遗---线性表
- 整理--数据结构--线性表
- 数据结构(线性表)
- 整理--数据结构--线性表
- 数据结构--顺序线性表
- 数据结构之线性表
- 数据结构-线性链表
- 数据结构-线性表
- 复习 [数据结构] ---- 线性表
- 数据结构---线性表
- 数据结构复习-线性表
- 数据结构之线性表
- 数据结构之线性表
- 线性链表---数据结构
- 数据结构—线性表
- 数据结构 线性表
- 数据结构----线性表
- 数据结构之线性表
- tabLayout的使用
- IntelliJ IDEA下的使用git
- MediaPlayer基本使用方式
- RecyclerView多条目展示
- 经典购物车
- 数据结构--线性表
- 购物车
- python学习笔记 一
- HTML5的结构
- SpringMVC之@PathVariable和RequestParam
- 2.6、映射
- android byte转换工具类--笔记
- 安卓SpannableString详解
- HTML+CSS+JavaScript小例题