数据结构专题——线性表
来源:互联网 发布:python meshgrid函数 编辑:程序博客网 时间:2024/05/16 12:22
一、线性表及其分类
(定义部分参考自《大话数据结构》及维基百科)
线性表(List / Linear List):零个或多个数据元素的有限序列。
线性表的基本操作(涉及算法中方法实现):
线性表初始化;
求线性表长度;
获取元素操作;
查找元素操作;
插入元素操作;
删除元素操作;
其他:判断线性表是否为空;清空线性表;
线性表可以存储结构特点分为两类:
1.顺序表 Sequence List(线性表的顺序存储结构):用一段地址连续的存储单元一次存储线性表的数据元素。
根据存储单元的内存开辟方式可以分为(根据不同的需求顺序表可以按照以下不同的方式实现):
1.1静态顺序表:保存数据元素的内存是在程序编译时就开辟的,空间大小是静态的。(针对C语言:可由数组实现。)
1.2动态顺序表:保存数据元素的内存是在程序运行时才开辟的,空间大小是动态的。(针对C语言:可由标准函数malloc和free动态实现。)
2.链表 Linked List(线性表的链式存储结构):由n个结点链结成的链表。
根据结点(node)的内存开辟方式可以分为(根据不同的需求链表可以按照以下不同的方式实现):
2.1.1静态链表:保存结点的内存是在程序编译时就开辟的,空间大小是静态的。(针对C语言:可由数组实现。)
2.1.2动态链表:保存结点的内存是在程序运行时才开辟的,空间大小是动态的。(针对C语言:可由标准函数malloc和free动态实现。)
根据结点(node)中存储逻辑关系的数据特征分类,常见有下面三种(根据不同的需求链表可以按照以下不同的方式实现):
(单链接或双链接,已排序或未排序,循环或非循环)
2.2.1单链表(singly linked list) :每个对象含关键字和后继指针
2.2.2双向链表(doubly linked list):每个对象含关键字,前驱指针和后继指针
2.2.3循环链表(circular linked list)(也可再分为单循环链表和双循环链表):首尾对象含有指针指向,形成圆环。
(上述更详细分类和术语可参考: http://zh.wikipedia.org/wiki/线性表http://en.wikipedia.org/wiki/Linked_list)
分析:对于线性表这一数据结构的分类,不同的作者有不同的分类方法,这里我采用我认为相对比较科学全面的分类方式,也尽量避免这些术语乱用。这些分类方式首先是脱离具体的程序设计语言去定义的,接着算法再利用特定的程序设计语言进行实现。我这边主要用C语言实现这些链表的数据结构和方法,供以后使用。
顺序表和链表优缺点比较:
顺序表:
优点: 随机存取时间复杂度为O(1);无需为表中元素之间的逻辑关系额外增加存储空间
缺点: 插入、删除操作需要移动大量的元素,时间复杂度为O(n);表的长度难以确定
链表:
优点: 插入、删除节点时不移动数据, 效率高,时间复杂度为O(1)
缺点: 存取时要遍历,效率低,时间复杂度为O(n)
因此,综上所诉,顺序存储结构适合频繁存取、查找,很少插入、删除的情况;链式存储适合频繁插入、删除,很少存取的情况;
二、线性表C实现
目标:
1.实现大多数类型的线性表数据结构,用于其他算法调用,以后需要使用现在未实现的线性表时在逐步加入;
2.算法具有通用,高效,简洁,注释充分四个特点,便于进行其他程序设计语言移植;
特点:
1.所有线性表的文件含有共用的文件头(list.h)(主要是通用的宏定义和标准函数库头文件包含,避免重复定义,方便维护);
2.由于不同类型的线性表使用的结构体名和函数名可能一致,各自含有相应的头文件(*.h)和实现文件(*.c),C语言不具有函数重载功能,因此只能独立使用这些线性表的数据类型(优点是避免因类型过多导致结构体名和函数名命名较乱,缺点是不能够在同一个文件中同时使用);
3.实现各个类型的线性表的基本操作。
注意:
1.实现线性表基本操作时函数的返回值值得考究,这里原则上尽量减少不必要返回值。
2.实现线性表基本操作时函数的返回状态可以用枚举类型实现(未实现)。
3.断言语句(assert)的参数需要认真考虑。
汇总:
头文件(list.h):
/** * @file list.h * @brief list header that has macro definition used by many types of list. * @author chenxilinsidney * @version 1.0 * @date 2015-01-19 */#ifndef __LIST_H__#define __LIST_H__#include <stdio.h>#include <stdlib.h>#include <string.h>// #define NDEBUG#include <assert.h>/// list return state#ifndef OK#define OK 1#endif#ifndef ERROR#define ERROR 0#endif#ifndef TRUE#define TRUE 1#endif#ifndef FALSE#define FALSE 0#endif/// list array maz length used by static sequence list, can be modified#define LIST_MAXSIZE 1000/// list initialize size used by dynamic sequence list, can be modified#define LIST_INIT_SIZE 1000/// list memory increated size used by dynamic sequence list, can be modified#define LIST_INCREMENT 2/// data type, can be modifiedtypedef int Status; ///< status data typetypedef int ElementType; ///< element data typetypedef int CommonType; ///< common data type#endif // __LIST_H__
静态顺序表(sequence_list_satic.h sequence_list_static.c):
/** * @file sequence_list_static.h * @brief static sequence list header. * @author chenxilinsidney * @version 1.0 * @date 2015-01-19 */#ifndef __SEQUENCE_LIST_STATIC_H__#define __SEQUENCE_LIST_STATIC_H__#include "list.h"/// static sequence list structuretypedef struct { ElementType data[LIST_MAXSIZE]; ///< list elements CommonType length; ///< list length}SqList;/// static sequence list method/// initialize listvoid InitList(SqList* L);/// detect if list is emptyStatus ListEmpty(SqList* L);/// clear listvoid ClearList(SqList* L);/// get list lengthCommonType ListLength(SqList* L);/// get element from the listStatus GetElem(SqList* L, CommonType index, ElementType* e);/// locate element of the indexCommonType LocateElem(SqList* L, ElementType e);/// insert element to the listStatus ListInsert(SqList* L, CommonType index, ElementType e);/// delete element from the listStatus ListDelete(SqList* L, CommonType index, ElementType* e);#endif // __SEQUENCE_LIST_STATIC_H__
/** * @file sequence_list_static.c * @brief static sequence list method implements. * The methods use <assert.h> to help debug the program. * @author chenxilinsidney * @version 1.0 * @date 2015-01-19 */#include "sequence_list_static.h"/** * @brief initialize the list. * * @param[in,out] L list struct pointer * */void InitList(SqList* L){ assert(L != NULL); /// initialize length only, ignore the list data L->length = 0;}/** * @brief detect if the list is empty. * * @param[in] L list struct pointer * * @return return TRUE if empty, else return FALSE */Status ListEmpty(SqList* L){ assert(L != NULL && L->length >= 0); /// always have length >= 0 if (L->length) return FALSE; else return TRUE;}/** * @brief clear the list. * * @param[in,out] L list struct pointer * */void ClearList(SqList* L){ assert(L != NULL); /// set length only, ignore the list data L->length = 0;}/** * @brief get list length. * * @param[in] L list struct pointer * * @return list length */CommonType ListLength(SqList* L){ assert(L != NULL && L->length >= 0); return L->length;}/** * @brief get element from the list. * * @param[in] L list struct pointer * @param[in] index the index from the list * @param[out] e the element by index * * @warning index begin from 1 * * @return return OK if success, else return ERROR */Status GetElem(SqList* L, CommonType index, ElementType* e){ assert(L != NULL && e != NULL && L->length >= 0); /// index should be in reasonable range if (index > L->length || index < 1) return ERROR; /// get element from list *e = L->data[index - 1]; return OK;}/** * @brief locate element by index. * * @param[in] L list struct pointer * @param[in] e the element to be located * * @warning index begin from 1 * * @return return the index of the element if success, else return 0 */CommonType LocateElem(SqList* L, ElementType e){ assert(L != NULL && L->length >= 0); CommonType i; for (i = 1; i <= L->length; i++) if (L->data[i - 1] == e) /// get index of the first found element from list return i; return 0;}/** * @brief insert element to the list at given index. * * @param[in,out] L list struct pointer * @param[in] index the index from the list * @param[in] e the element to be insert * * @warning index begin from 1 * * @return return OK if success, else return ERROR */Status ListInsert(SqList* L, CommonType index, ElementType e){ assert(L != NULL && L->length >= 0); /// list length and index should be in reasonable range if (L->length == LIST_MAXSIZE || index > (L->length + 1) || index < 1) return ERROR; /// move the element after the index position to next position CommonType i; for (i = L->length - 1; i >= index - 1; i--) L->data[i + 1] = L->data[i]; /// increase list length L->length++; /// insert element L->data[index - 1] = e; return OK;}/** * @brief delete element from the list. * * @param[in,out] L list struct pointer * @param[in] index the index from the list * @param[out] e the element to be deleted * * @warning index begin from 1 * * @return return OK and set e if success, else return ERROR */Status ListDelete(SqList* L, CommonType index, ElementType* e){ assert(L != NULL && e != NULL && L->length >= 0); /// index should be in reasonable range if (index > L->length || index < 1) return ERROR; /// get deleted element *e = L->data[index - 1]; /// move the element after the index position to previous position CommonType i; for (i = index; i < L->length; i++) L->data[i - 1] = L->data[i]; /// decrease list length L->length--; return OK;}
动态顺序表(sqlist_dynamic.h sqlist_dynamic.c):
/** * @file sequence_list_dynamic.h * @brief dynamic sequence list header. * @author chenxilinsidney * @version 1.0 * @date 2015-01-19 */#ifndef __SEQUENCE_LIST_DYNAMIC_H__#define __SEQUENCE_LIST_DYNAMIC_H__#include "list.h"/// dynamic sequence list structuretypedef struct { ElementType* data; ///< list elements CommonType length; ///< list length CommonType listsize; ///< list size mallocated}SqList;/// dynamic sequence list method/// initialize listvoid InitList(SqList* L);/// destroy listvoid DestroyList(SqList* L);/// detect if list is emptyStatus ListEmpty(SqList* L);/// clear listvoid ClearList(SqList* L);/// get list lengthCommonType ListLength(SqList* L);/// get element from the listStatus GetElem(SqList* L, CommonType index, ElementType* e);/// locate element of the indexCommonType LocateElem(SqList* L, ElementType e);/// insert element to the listStatus ListInsert(SqList* L, CommonType index, ElementType e);/// delete element from the listStatus ListDelete(SqList* L, CommonType index, ElementType* e);#endif // __SEQUENCE_LIST_DYNAMIC_H__
/** * @file sequence_list_dynamic.c * @brief dynamic sequence list method implements. * The methods use <assert.h> to help debug the program. * @author chenxilinsidney * @version 1.0 * @date 2015-01-19 */#include "sequence_list_dynamic.h"/** * @brief initialize the list. * * @param[in,out] L list struct pointer * */void InitList(SqList* L){ assert(L != NULL); /// initialize length list size and malloc memory if ((L->data = malloc(LIST_INIT_SIZE * sizeof(ElementType))) == NULL) { assert(0); exit(EXIT_FAILURE); } L->length = 0; L->listsize = LIST_INIT_SIZE;}/** * @brief destroy the list. * * @param[in,out] L list struct pointer * */void DestroyList(SqList* L){ assert(L != NULL && L->length >= 0 && L->length <= L->listsize); /// clear length list size and free memory free(L->data); L->data = NULL; L->length = 0; L->listsize = 0;}/** * @brief detect if the list is empty. * * @param[in] L list struct pointer * * @return return TRUE if empty, else return FALSE */Status ListEmpty(SqList* L){ assert(L != NULL && L->length >= 0 && L->length <= L->listsize); /// always have length >= 0 if (L->length) return FALSE; else return TRUE;}/** * @brief clear the list. * * @param[in,out] L list struct pointer * */void ClearList(SqList* L){ assert(L != NULL); /// set length only, ignore the list data L->length = 0;}/** * @brief get list length. * * @param[in] L list struct pointer * * @return list length */CommonType ListLength(SqList* L){ assert(L != NULL && L->length >= 0 && L->length <= L->listsize); return L->length;}/** * @brief get element from the list. * * @param[in] L list struct pointer * @param[in] index the index from the list * @param[out] e the element by index * * @warning index begin from 1 * * @return return OK if success, else return ERROR */Status GetElem(SqList* L, CommonType index, ElementType* e){ assert(L != NULL && e != NULL && L->length >= 0 && L->length <= L->listsize); /// index should be in reasonable range if (index > L->length || index < 1) return ERROR; /// get element from list *e = L->data[index - 1]; return OK;}/** * @brief locate element by index. * * @param[in] L list struct pointer * @param[in] e the element to be located * * @warning index begin from 1 * * @return return the index of the element if success, else return 0 */CommonType LocateElem(SqList* L, ElementType e){ assert(L != NULL && L->length >= 0 && L->length <= L->listsize); CommonType i; for (i = 1; i <= L->length; i++) if (L->data[i - 1] == e) /// get index of the first found element from list return i; return 0;}/** * @brief insert element to the list at given index. * * @param[in,out] L list struct pointer * @param[in] index the index from the list * @param[in] e the element to be insert * * @warning index begin from 1 * * @return return OK if success, else return ERROR */Status ListInsert(SqList* L, CommonType index, ElementType e){ assert(L != NULL && L->length >= 0 && L->length <= L->listsize); /// list length and index should be in reasonable range if (index > (L->length + 1) || index < 1) return ERROR; /// malloc memory if not enough if (L->length == L->listsize) { ElementType* newbase = (ElementType*)realloc( L->data, (L->listsize + LIST_INCREMENT) * sizeof(ElementType)); if (newbase == NULL) { assert(0); exit(EXIT_FAILURE); } L->data = newbase; L->listsize += LIST_INCREMENT; } /// move the element after the index position to next position CommonType i; for (i = L->length - 1; i >= index - 1; i--) L->data[i + 1] = L->data[i]; /// increase list length L->length++; /// insert element L->data[index - 1] = e; return OK;}/** * @brief delete element from the list. * * @param[in,out] L list struct pointer * @param[in] index the index from the list * @param[out] e the element to be deleted * * @warning index begin from 1 * * @return return OK and set e if success, else return ERROR */Status ListDelete(SqList* L, CommonType index, ElementType* e){ assert(L != NULL && e != NULL && L->length >= 0 && L->length <= L->listsize); /// index should be in reasonable range if (index > L->length || index < 1) return ERROR; /// get deleted element *e = L->data[index - 1]; /// move the element after the index position to previous position CommonType i; for (i = index; i < L->length; i++) L->data[i - 1] = L->data[i]; /// decrease list length L->length--; return OK;}
动态单链表(linked_list_dynamic.h linked_list_dynamic.c):
/** * @file linked_list_dynamic.h * @brief dynamic linked list header. * the data was not in the first node. * @author chenxilinsidney * @version 1.0 * @date 2015-01-19 */#ifndef __LINKED_LIST_DYNAMIC_H__#define __LINKED_LIST_DYNAMIC_H__#include "list.h"/// node structuretypedef struct Node{ ElementType data; ///< data in the node struct Node* next; ///< pointer to next node}Node;/// define single linked listtypedef Node* LinkList;/// dynamic linked list method/// initialize listvoid InitList(LinkList* L, CommonType size);/// destroy listvoid DestroyList(LinkList* L);/// detect if list is emptyStatus ListEmpty(LinkList* L);/// clear listvoid ClearList(LinkList* L);/// get list lengthCommonType ListLength(LinkList* L);/// get element from the listStatus GetElem(LinkList* L, CommonType index, ElementType* e);/// locate element of the indexCommonType LocateElem(LinkList* L, ElementType e);/// insert element to the listStatus ListInsert(LinkList* L, CommonType index, ElementType e);/// delete element from the listStatus ListDelete(LinkList* L, CommonType index, ElementType* e);#endif // __LINKED_LIST_DYNAMIC_H__
/** * @file linked_list_dynamic.c * @brief dynamic linked list method implements. * The methods use <assert.h> to help debug the program. * @author chenxilinsidney * @version 1.0 * @date 2015-01-19 */#include "linked_list_dynamic.h"/** * @brief initialize the list.insert node in the head of list. * The method can be alse modified to insert node in the tail * of list. * * @param[in,out] L list struct pointer * @param[in] size list data size * */void InitList(LinkList* L, CommonType size){ assert(size >= 0); /// initialize first node if ((*L = (LinkList)malloc(sizeof(Node))) == NULL) { assert(0); exit(EXIT_FAILURE); } (*L)->next = NULL; /// initialize other node LinkList new_node; while (size--) { /// add new node to the head of the list if ((new_node = (LinkList)malloc(sizeof(Node))) == NULL) { assert(0); exit(EXIT_FAILURE); } new_node->data = 0; new_node->next = (*L)->next; (*L)->next = new_node; }}/** * @brief destroy the list. * * @param[in,out] L list struct pointer * */void DestroyList(LinkList* L){ assert(L != NULL); /// pointer to the first node LinkList q, p = (*L); /// free memory while (p) { q = p->next; free(p); p = q; } /// set first node to null *L = NULL;}/** * @brief detect if the list is empty. * * @param[in] L list struct pointer * * @return return TRUE if empty, else return FALSE */Status ListEmpty(LinkList* L){ assert(L != NULL); /// check the first data node if ((*L)->next) return FALSE; else return TRUE;}/** * @brief clear the list. * * @param[in,out] L list struct pointer * */void ClearList(LinkList* L){ assert(L != NULL); /// pointer to the first data node LinkList q, p = (*L)->next; /// free memory while (p) { q = p->next; free(p); p = q; } /// set first data node to NULL (*L)->next = NULL;}/** * @brief get list length. * * @param[in] L list struct pointer * * @return list length */CommonType ListLength(LinkList* L){ assert(L != NULL); /// pointer to the first data node CommonType length = 0; LinkList p = (*L)->next; /// pointer to next node while (p) { p = p->next; length++; } return length;}/** * @brief get element from the list. * * @param[in] L list struct pointer * @param[in] index the index from the list * @param[out] e the element by index * * @warning index begin from 1 * * @return return OK if success, else return ERROR */Status GetElem(LinkList* L, CommonType index, ElementType* e){ assert(L != NULL && e != NULL); /// pointer to the first data node CommonType j = 1; LinkList p = (*L)->next; /// pointer to node of index while (p && j < index) { /// pointer to next node p = p->next; j++; } /// can not get the element by index if(!p || j > index) return ERROR; /// get element from list *e = p->data; return OK;}/** * @brief locate element by index. * * @param[in] L list struct pointer * @param[in] e the element to be located * * @warning index begin from 1 * * @return return the index of the element if success, else return 0 */CommonType LocateElem(LinkList* L, ElementType e){ assert(L != NULL); /// pointer to the first data node CommonType index = 0; LinkList p = (*L)->next; /// pointer to next node while (p) { index++; /// get index of the first found element from list if(p->data == e) return index; p = p->next; } return 0;}/** * @brief insert element to the list at given index. * * @param[in,out] L list struct pointer * @param[in] index the index from the list * @param[in] e the element to be insert * * @warning index begin from 1 * * @return return OK if success, else return ERROR */Status ListInsert(LinkList* L, CommonType index, ElementType e){ assert(L != NULL); CommonType j = 1; /// pointer to the first node LinkList s, p = *L; /// pointer to node of index while (p->next && j < index) { p = p->next; j++; } /// can not get the location by index if(!p->next || j > index) return ERROR; /// malloc memory if ((s = (LinkList)malloc(sizeof(Node))) == NULL) { assert(0); exit(EXIT_FAILURE); } /// insert element s->data = e; s->next = p->next; p->next = s; return OK;}/** * @brief delete element from the list. * * @param[in,out] L list struct pointer * @param[in] index the index from the list * @param[out] e the element to be deleted * * @warning index begin from 1 * * @return return OK and set e if success, else return ERROR */Status ListDelete(LinkList* L, CommonType index, ElementType* e){ assert(L != NULL && e != NULL); CommonType j = 1; /// pointer to the first node LinkList q, p = *L; /// pointer to node of index while (p->next && j < index) { p = p->next; j++; } /// can not get the location by index if (!(p->next) || j > index) return ERROR; /// get deleted element q = p->next; p->next = q->next; *e = q->data; free(q); return OK;}
单链表一些知识补充:
头结点:链表的第一个有效结点前面的结点,头结点并不存放有效数据,也就是数据域为空,加头结点的主要目的是为了方便链表的操作。
首节点:链表的第一个有效结点,结点包含数据域和指针域。
尾结点:尾结点的指针域为空。
头指针:指向头结点的指针变量,它存放了头结点的地址(在这里注意一下,指针变量存放的是地址,也就是说头指针存放的是头结点的地址,一般通过头指针对链表进行操作)。
- 数据结构专题——线性表
- 数据结构第三次实验——线性表专题在线评测
- 数据结构与算法专题之线性表——链表(二)双向链表
- 数据结构与算法专题之线性表——链表(三)循环链表
- 数据结构专题——线性表之顺序表及其Java实现
- 数据结构与算法专题之线性表——链表(一)单链表
- 数据结构与算法专题之线性表——栈及其应用
- 数据结构与算法专题之线性表——队列及其应用
- 数据结构专题——线性表之单链表及其Java实现
- 数据结构专题——线性表之双链表及其Java实现
- 数据结构—线性表
- 数据结构—线性表
- 数据结构—线性表
- 数据结构—线性表
- 【数据结构专题】线性表之顺序表
- 【数据结构专题】线性表之单链表
- [数据结构]线性结构——线性表
- 数据结构——线性表
- 对图中一些概念的区分
- ADB常用命令笔记
- 实现实现易信的圆形图像和对话列表的图像显示部分
- Android Toolbar跟随ListView滑动隐藏和现实
- jQuery在线手册
- 数据结构专题——线性表
- clientHeight、offsetHeight、scrollHeight
- ASCII, BIG5, GBK, Unicode, UTF之间的关系
- MHA高可用架构搭建指南V1.0
- Qt 数据类型的转换
- 图文并茂、手把手教你怎么将Java项目与Flex4整合
- 聊聊什么是创业
- 宏定义
- 组播相关