数据结构之线性结构

合集下载

数据结构之线性结构和非线性结构

数据结构之线性结构和非线性结构

数据结构之线性结构和⾮线性结构线性结构:⼀、概念1. 线性结构作为最常⽤的数据结构,其特点是数据元素之间存在⼀对⼀的线性关系。

2. 线性结构拥有两种不同的存储结构,即顺序存储结构和链式存储结构。

顺序存储的线性表称为顺序表,顺序表中的存储元素是连续的,链式存储的线性表称为链表,链表中的存储元素不⼀定是连续的,元素节点中存放数据元素以及相邻元素的地址信息。

3. 线性结构中存在两种操作受限的使⽤场景,即队列和栈。

栈的操作只能在线性表的⼀端进⾏,就是我们常说的先进后出(FILO),队列的插⼊操作在线性表的⼀端进⾏⽽其他操作在线性表的另⼀端进⾏,先进先出(FIFO),由于线性结构存在两种存储结构,因此队列和栈各存在两个实现⽅式。

⼆、部分实现1. 顺序表(顺序存储) 按照我们的习惯,存放东西时,⼀般是找⼀块空间,然后将需要存放的东西依次摆放,这就是顺序存储。

计算机中的顺序存储是指在内存中⽤⼀块地址连续的空间依次存放数据元素,⽤这种⽅式存储的线性表叫顺序表其特点是表中相邻的数据元素在内存中存储位置也相邻,如下图:1 // 倒置线性表2 public void Reverse()3 {4 T tmp = default(T);56 int len = GetLength() - 1;7 for (int i = 0; i <= len / 2; i++)8 {9 if (i.Equals(len - i))10 {11 break;12 }1314 tmp = data[i];15 data[i] = data[len - i];16 data[len - i] = tmp;17 }18 }2. 链表(链式存储) 假如我们现在要存放⼀些物品,但是没有⾜够⼤的空间将所有的物品⼀次性放下(电脑中使⽤链式存储不是因为内存不够先事先说明⼀下...,具体原因后续会说到),同时设定我们因为脑容量很⼩,为了节省空间,只能记住⼀件物品位置。

《数据结构》线性结构实验报告

《数据结构》线性结构实验报告

《数据结构》线性结构实验报告2、源程序:#include <stdio.h>#include<stdlib.h>#define MAXSIZE 1024typedef int elemtype;typedef struct SequenStack{elemtype data[MAXSIZE];int top;}SequenStack;SequenStack * Init_SequenStack(){SequenStack * S;S = (SequenStack *)malloc(sizeof(SequenStack));if (S == NULL)return S;S->top = -1;return S;}int SequenStack_Empty(SequenStack * S)//判栈空{if (S->top == -1){return 1;}{int a;printf("请以十进制输入一个数:\n");scanf_s("%d", &a);printf("转化为二进制为:");Conversion(a);printf("\n");}运行结果:3、源程序:#include<stdio.h>#include<stdlib.h>#include<string.h>typedef struct node{char data;struct node* next;}LinkStack;//初始化LinkStack* Init_LinkStack(){LinkStack* top;top = (LinkStack*)malloc(sizeof(LinkStack));top->next = NULL;return top;}//入栈void Push_LinkStack(LinkStack* top, char x){LinkStack* node;node = (LinkStack*)malloc(sizeof(LinkStack));node->data = x;node->next = top->next;top->next = node;}运行结果:4、源程序:#include <stdio.h>#include<stdlib.h>#include<string.h>#define MAXSIZE 20typedef int elemtype;typedef struct QueueNode{elemtype data;struct QueueNode* next;}LinkedQueueNode;typedef struct LQueue{LinkedQueueNode* front;LinkedQueueNode* rear;}LQueue, *LinkedQueue;typedef struct Person{char name[MAXSIZE];char sex;}Person;typedef char* ElemType;//链队初始化LinkedQueue Init_LinkedQueue(){LinkedQueue Q = (LinkedQueue)malloc(sizeof(LQueue));LinkedQueueNode * head = (LinkedQueueNode *)malloc(sizeof(LinkedQueueNode));if (head != NULL && Q != NULL){head->next = NULL;Q->front = head;Q->rear = head;printf("输入参与者的姓名,性别\n");for (i = 0; i < num; i++){printf("输入第%d个舞者的名字:\n", i + 1);scanf_s("%s", &dancer[i].name, 10);printf("输入第%d个人的性别(F/M):\n", i + 1);scanf_s("%s", &dancer[i].sex, 10);while (dancer[i].sex != 'F' && dancer[i].sex != 'M'){printf("输入错误,请重新输入第%d个人的性别(F/M):\n", i + 1);scanf_s("%s", &dancer[i].sex, 10);}}DancePartner(dancer, num);break;case 0:printf("感谢你的使用!\n");break;default:printf("无此选项!\n");break;}} while (n != 0);return 0;}运行结果:。

线性数据结构例题分析

线性数据结构例题分析

算法分析(朴素的算法): 对于每个大小为k的区间,都要计算最大值和最小值 时间复杂度:O(n * k)
位置 数值
1 1
2 3
3 -1 -1
4 -3 -3 -3
5 5 -3 5
6 3 -3 3
7 6 3 6
8 7 3 7
min
队列: 1 3
-1
观察队列中元素离开队列的情况:
1.元素Vi从队尾离开队列:
第i+1个元素以及它后面的元素依次前移。
其中,2、3操作中都可能需要移动大量元素。
总复杂度:O(n * m)。
Байду номын сангаас 5 1 2 2 2 7 1 2 3 3 6 31 23 14 5 7
1 3
链表: 元素数组:data[maxn]; 指针数组:next[maxn]; //元素data[i]的后继元素所在位置是next[i] 头结点指针:head 不要求逻辑上相邻的元素存储位置也相邻,不能随机存储。 5 1 2 2 2 7 1 2 3 3 1 3
算法分析: 维护三个数组q1,q2,q3; 取q2、q3队首元素的较小者k,加入q1,相应队列的队首位置后移, 2*k+1、3*k+1分别加入q2、q3;
直到q1中的元素个数达到n个。
实际上,q2、q3中的元素都来自于q1,只要维护two、three两个位置,
表示q2中的下一个数由q1[two]*2+1得到,q3中的下一个数由
j插在i的右侧:
ll[j] = i; rr[j] = rr[i];
ll[rr[i]] = j; rr[i] = j;
删除i: rr[ll[i]] = rr[i]; ll[rr[i]] = ll[i];

数据结构 线性表

数据结构 线性表

(9) Status NextElem_Sq(SqList L, ElemType cur_e, ElemaType &next_e)
//若cur_e是线性表L的元素且不是最后一个,返回它的后继 { for (i=0; i<L.length-1; i++) if (cur_e==L.elem[i]) { next_e=L.elem[i+1]; return OK; } return ERROR; }//NextElem_Sq O(n)
抽象数据类型 唯 一 数据的逻辑结构 确 操作的定义 定
集合 *
线性表
特殊线性表 扩展线性表
线性结构
树形结构 图形结构
灵 活 数据的存储结构 操作的实现 设 计
顺序存储 链式存储 散列(哈希)存储
数据的基本操作:针对结构、针对元素、针对状态
数据结构---第二章 线性表 1
第二章 线性表
2.1 2.2 2.3 2.4
数据结构---第二章 线性表
9
2.2 线性表的顺序存储结构(顺序表)
起始地址为b、最多可容纳maxlen个元素的线性表
下标 存储地址
0
1
b b+c
b+(i-1)c
a1 a2
ai
c个存储单元
i-1
LOC(ai)=LOC(a1)+(i-1)c LOC(ai)=LOC(ai-1)+c
n-1
b+(n-1)c
n-1
int LocateElem_Sq(SqList L, ElemType e, (7) Status (*compare)(ElemType,ElemType) ) //在线性表L中查找第1个值与e满足 //compare()的元素的位序 { for (i=0; i<L.length; i++) L.elem[i]==e if ( (*compare)(L.elem[i],e) ) return i+1; return 0 ; //作为未找到的特殊标记 } // LocateElem_Sq O(n) P25-2.6

数据结构-线性结构

数据结构-线性结构

数据结构-线性结构线性表线性表是最简单最常见的数据结构,属于逻辑结构;线性表有两种实现⽅式(存储⽅式),分别是顺序实现和链接实现;定义:线性表是由n(>=0)个数据元素组成的有限序列,数据元素的个数n定义为表的长度;术语:前驱, 后继, 直接前驱, 直接后继, 长度, 空表案例:线性表⽤L表⽰,⼀个⾮空线性表可记为L = (a1,a2,..an);a1后⾯的称为a1的后继an前⾯的称为an的前驱a1为起始节点,an为终端节点,任意相邻的两个元素,如a1和a2,a1是a2的直接前驱,a2是a1的直接后继;线性表中元素个数即表的长度,此处为n;表中没有任何元素时,称为空表除了⾸节点和尾节点之外,每个节点都有且只有⼀个直接前驱和直接后继,⾸节点没有前驱,尾节点没有后继;节点之间的关系属于⼀对⼀;线性表的基本运算初始化Initiate(L) 建⽴⼀个空表L(),L不包含数据元素求表长度Length(L) 返回线性表的长度取表元素Get(L,i) 返回线性表的第i个元素,i不满⾜1<=i<=Length(L)时,返回特殊值;定位Locate(L,x)查找x在L中的节点序号,若有多个匹配的返回第⼀个,若没有匹配的返回0;插⼊Insert(L,x,i)将x插⼊到L的第i个元素的前⾯(其他元素往后挪),参数i取值范围为1<=i<=Length(L)+1;运算结束后表长度+1;删除Delete(L,i)删除表L中的第i个元素,i有效范围1<=i<=Length(L);操作结束后表长度-1强调:上述的第i个指的是元素的序号从1开始,⽽不是下标从0开始;另外:插⼊操作要保证操作后数据还是⼀个接着⼀个的不能出现空缺;线性表的顺序存储实现线性表是⼀种逻辑结构,可以通过顺序存储结构来实现,即:将表中的节点⼀次存放在计算机内存中⼀组连续的存储单元中,数据元素在线性表中的邻接关系决定了它们在存储空间中的存储位置;换句话说逻辑结构中相邻的两个节点的实际存储位置也相邻;⽤顺序存储结构实现的线性表也称之为为顺序表,⼀般采⽤数组来实现;图⽰:⼤⼩与长度:线性表的⼤⼩:指的是最⼤能存储的元素个数线性表的长度:指的是当前已存储的个数⽰例:c语⾔实现:#include <stdio.h>//初始化操作:const MAX_SIZE = 5;//最⼤长度typedef struct list {int data[MAX_SIZE];//数组int length;//当前数据长度};//获取targert在表中的位置int locate(struct list *l,int target){for (int i = 0;i < l->length;i++){if (target == l->data[i]){return i + 1;}}return 0;}//获取第loc个元素int get(struct list *l,int loc){if (loc < 1 || loc > l->length){printf("error:位置超出范围\n");return -1;}else{return l->data[loc-1];}}//插⼊⼀个元素到第loc个位置上void insert(struct list *l,int data,int location){if (l->length == MAX_SIZE){printf("errolr:表容量已满\n");return;}if (location < 1 || location > l->length+1){printf("error:位置超出范围\n");return;}//⽬标位置后⾯的内容以此往后挪for (int i = l->length; i >= location; i--) {l->data[i] = l->data[i-1];}//在⽬标位置放⼊新的数据l->data[location-1] = data;l->length+=1;//长度加1}//删除第loc个元素,从⽬标位置往后的元素⼀次向前移动void delete(struct list *l,int loc){if (loc < 1|| loc > l->length){printf("error:位置超出范围\n");return;}//⽬标位置及后⾯的所有元素全部向后移动for (;loc < l->length; ++loc) {l->data[loc-1] = l->data[loc];}l->length-=1;}//打印所有元素测试⽤void show(struct list l){for (int i = 0; i < l.length; ++i) {printf("%d\n",l.data[i]);}}//测试int main() {struct list alist = {};insert(&alist,100,alist.length+1);insert(&alist,200,alist.length+1);insert(&alist,300,alist.length+1);insert(&alist,400,alist.length+1);delete(&alist,1);printf("%d\n",alist.length);show(alist);printf("%d\n",get(&alist,4));printf("%d\n", locate(&alist,300));printf("%d\n", get(&alist,1));return 0;}插⼊算法分析:假设线性表中含有n个元素,在插⼊元素时,有n+1个位置可以插⼊,因为要保证数据是连续的每个位置插⼊数据的概率是: 1/(n+1)在i的位置插⼊时,要移动的元素个数为:n - i + 1算法时间复杂度为:O(n)删除算法分析:假设线性表中含有n个元素,在删除元素时,有n个位置可以删除每个位置插⼊数据的概率是: 1/n在i的位置删除时,要移动的元素个数为:n - i算法时间复杂度为:O(n)插⼊与删除的不⾜顺序表在进⾏插⼊和删除操作时,平均要移动⼤约⼀半的数据元素,当存储的数据量⾮常⼤的时候,这⼀点需要特别注意;简单的说,顺序表在插⼊和删除时的效率是不够好的;特别在数据量⼤的情况下;顺序表总结:1.顺序表是⼀维数组实现的线性表2.逻辑上相邻的元素,在存储结构中也是相邻的3.顺序表可实现随机读取优缺点:优点:⽆需为了表⽰元素直接的逻辑关系⽽增加额外的存储空间可⽅便的随机存取表中的任⼀节点缺点:插⼊和删除运算不⽅便,需要移动⼤量的节点顺序表要求占⽤连续的存储空间,必须预先分配内存,因此当表中长度变化较⼤时,难以确定合适的存储空间⼤⼩;顺序表节点存储地址计算:设第i个节点的存储地址为x设顺序表起始地址为loc,每个数据元素占L个存储单位计算公式为:x = loc + L * (i-1)如 loc = 100 i = 5 L = 4 则 x = 116线性表的链接存储实现线性表也可通过链接存储⽅式来实现,⽤链接存储⽅式实现的线性表也称为链表 Link List链式存储结构:1.可⽤任意⼀组存储单元来存储数据2.链表中节点的逻辑次序与物理次序不⼀定相同3.每个节点必须存储其后继节点的地址信息(指针)图⽰:单链表单链表指的是只能沿⼀个⽅向查找数据的链表,如上图每个节点由两个部分(也称为域)组成data域存放节点值得数据域next域存放节点的直接后继的地址的指针域(也称为链域)节点结构:每个节点只知道⾃⼰后⾯⼀个节点却不知道⾃⼰前⾯的节点所以称为单链表图⽰:带有head节点的单链表:单链表的第⼀个节点通常不存储数据,称为头指针,使⽤头指针来存储该节点的地址信息,之所以这么设计是为了⽅便运算;单链表特点:其实节点也称为⾸节点,没有前驱,所以头指针要指向该节点,以保证能够访问到起始节点;头指针可以唯⼀确定⼀个链表,单链表可以使⽤头指针的名称来命名;终端节点也称尾节点,没有后继节点,所以终端节点的next域为NULL;除头结点之外的⼏点称为表结点为⽅便运算,头结点中不存储数据单链表数据结构定义//数据结构定义typedef struct node {struct node *next;int data,length;} Node, *LinkList;/** typedef 是⽤来取别名的* Node 是struct node 的别名* *LinkList 是 struct node *的别名* 后续使⽤就不⽤在写struct关键字了*/运算:初始化⼀个空链表有⼀个头指针和⼀个头结点构成假设已定义指针变量L,使L指向⼀个头结点,并使头结点的next为NULL//时间复杂度 :O(1)LinkList initialLinkList() {// 定义链表的头结点LinkList head;//申请空间head = malloc(sizeof(struct node));//使头结点指向NULLhead->next = NULL;return head;}求表长从头指针开始遍历每个节点知道某个节点next为NULL为⽌,next不为空则个数len+1;//求表长时间复杂度 :O(n)int length(LinkList list){int len = 0;Node *c = list->next;while(c != NULL){len+=1;c = c->next;}return len;}读表元素给定⼀个位置n,获取该位置的节点遍历链表,过程中若某节点next为NULL或已遍历个数index=n则结束循环//从链表中获取第position个位置的节点时间复杂度 :O(n)Node *get(LinkList list, int position) {Node *current;int index = 1;current = list->next;//如果下⾯还有值并且还没有到达指定的位置就继续遍历要和查找元素区别开这就是⼀直往后遍历直到位置匹配就⾏了 while (current != NULL && index < position) {current = current->next;index += 1;}if (index == position) {return current;}return NULL;}定位对给定表元素的值,找出这个元素的位置遍历链表,若某节点数据域与要查找的元素data相等则返回当前遍历的次数index//求表head中第⼀个值等于x的结点的序号(从1开始),若不存在这种结点,返回结果为0 时间复杂度 :O(n)int locate(LinkList list,int data){int index = 1;Node *c;c = list->next;while (c != NULL){if (c->data == data){return index;}index+=1;c = c->next;}return 0;}插⼊在表的第i个数据元素结点之前插⼊⼀个以x为值的新结点new获取第i的节点的直接前驱节点pre(若存在),使new.next = pre.next;pre.next = new;//在表head的第i个数据元素结点之前插⼊⼀个以x为值的新结点时间复杂度 :O(n)void insert(LinkList list, int position, int data) {Node *pre, *new;if (position == 1) {//若插⼊位置为1 则表⽰要插⼊到表的最前⾯即head的后⾯pre = list;} else {//pre表⽰⽬标位置的前⼀个元素所以-1pre = get(list, position - 1);if (pre == NULL) {printf("error:插⼊的位置超出范围");exit(0);}}new = malloc(sizeof(Node));new->data = data;new->next = pre->next;pre->next = new;list->length += 1;}删除删除给定位置的节点获取⽬标节点target的直接前驱节点pre(若pre与⽬标都有效),pre.next = target.next; free(target);//删除链表中第position个位置的节点时间复杂度 :O(n)void delete(LinkList list,int position){//获取要删除节点的直接前驱Node *pre;if (position == 1){ //如要删除的节点是第⼀个那直接前驱就是头结点pre = list;}else{pre = get(list,position-1);}////如果⽬标和前驱都存在则执⾏删除if (pre != NULL && pre->next != NULL){Node *target = pre->next; //要删除的⽬标节点//直接前驱的next指向⽬标的直接后继的nextpre->next = target->next;free(target);printf("info: %d被删除\n",target->data);list->length -= 1;}else{printf("error:删除的位置不正确!");exit(1);}}创建具备指定数据节点的链表//效率⽐较差算法时间复杂度 :O(n^2)LinkList createLinkList1(){LinkList list = initialLinkList();int a;//输⼊的数据int index = 1; //记录当前位置scanf("%d",&a);while (a != -1){ // O(n)insert(list,index++,a); // O(n^2) 每次都要从头遍历链表scanf("%d",&a);}return list;}//尾插算法记录尾节点从⽽避免遍历时间复杂度 :O(n)LinkList createLinkList2(){LinkList list = initialLinkList();int a;//输⼊的数据Node *tail = list;//当前的尾部节点scanf("%d",&a);while (a != -1){ // O(n)Node * newNode = malloc(sizeof(Node)); //新节点newNode->next = NULL;newNode->data = a;tail->next = newNode;//尾部节点的next指向新节点tail = newNode;//新节点作为尾部节点scanf("%d",&a);}return list;}//头插算法每次插到head的后⾯,不⽤遍历但是顺序与插⼊时相反时间复杂度 :O(n)LinkList createLinkList3(){LinkList list = initialLinkList();int a;//输⼊的数据Node * head = list;scanf("%d",&a);while (a != -1){ // O(n)Node * newNode = malloc(sizeof(Node)); //新节点newNode->next = NULL;newNode->data = a;newNode->next = head->next;//将原本head的next 交给新节点;head->next = newNode;//在把新节点作为head的next;scanf("%d",&a);}return list;}优缺点优点:在⾮终端节点插⼊删除时⽆需移动其他元素⽆需预分配空间,⼤⼩没有限制(内存够的情况)缺点:⽆法随机存取读取数据慢链表与顺序表的对⽐:操作顺序表链表读表元O(1)O(n)定位O(n)O(n)插⼊O(n)O(n)删除O(n)O(n)。

数据结构分类

数据结构分类

数据结构分类数据结构是计算机科学中的一个重要概念,它用于存储和组织数据以便有效地访问和操作。

根据数据元素之间的关系和操作的性质,数据结构可以被分为不同的类型。

本文将介绍常见的数据结构分类,并讨论每种分类的特点和应用。

1. 线性结构线性结构是最简单且最常见的数据结构之一,其特点是所有的数据元素都排列成一条直线。

线性结构包括顺序表、链表、栈和队列等。

顺序表是一种用连续的存储单元依次存储数据元素的结构,可以通过下标直接访问元素。

链表则是通过指针将元素链接在一起,允许在任意位置插入和删除元素。

栈是一种特殊的线性结构,只允许在一端插入和删除元素,满足后进先出(LIFO)的原则。

队列也是一种特殊的线性结构,只允许在一端插入,在另一端删除,满足先进先出(FIFO)的原则。

2. 非线性结构非线性结构中的数据元素并不是一对一的关系,而是多对多的关系。

其中最常见的非线性结构是树和图。

树结构由一组节点和边组成,每个节点可以有多个子节点,但只有一个父节点,顶端的节点称为根节点。

树结构常用于表示层次关系,例如文件系统。

图结构是一种包含节点和边的集合,节点之间的连接关系可以是任意的,图结构可以用来表示各种复杂的关系网络,比如社交网络和网页链接。

3. 数据结构的扩展除了线性结构和非线性结构,还有一些特殊的数据结构用于解决特定的问题。

常见的扩展结构包括散列表、堆、树状数组和并查集等。

散列表采用哈希函数将元素映射到一个存储位置,以实现快速的插入、删除和查找操作。

堆是一种优先级队列的实现方式,可以高效地找到最大或最小元素。

树状数组可以用于快速求取前缀和等操作。

并查集用于维护不相交集合的数据结构,常用于解决连通性问题。

总结数据结构是计算机科学中非常重要的概念,不同的数据结构适用于解决不同类型的问题。

线性结构适用于有序的数据关系,非线性结构适用于多对多的关系。

此外,扩展的数据结构可以帮助我们更高效地解决一些特殊问题。

掌握不同数据结构的特点和应用,对于算法设计和程序优化至关重要。

数据结构之线性表

数据结构之线性表
什么是线性表
线性表是最简单、最基本、最常用的数据结构。线性表是线性结构的抽象(Abstract),线性 结构的特点是结构中的数据元素之间存在一对一的线性关系。这种一对一的关系指的是数据 元素之间的位置关系,即:( 1)除第一个位置的数据元素外,其它数据元素位置的前面都 只有一个数据元素;( 2)除最后一个位置的数据元素外,其它数据元素位置的后面都只有 一个元素。也就是说,数据元素是一个接一个的排列。因此,可以把线性表想象为一种数据 元素序列的数据结构。
单链表的存储
链表是用一组任意的存储单元来存储线性表中的数据元素(这组存储单元可以是连续的,也 可以是不连续的)。那么,怎么表示两个数据元素逻辑上的相邻关系呢?即如何表示数据元 素之间的线性关系呢?为此,在存储数据元素时,除了存储数据元素本身的信息外,还要存 储与它相邻的数据元素的存储地址信息。这两部分信息组成该数据元素的存储映像(Image), 称为结点(Node)。把存储据元素本身信息的域叫结点的数据域(Data Domain),把存储与它 相邻的数据元素的存储地址信息的域叫结点的引用域(Reference Domain)。因此,线性表 通过每个结点的引用域形成了一根“链条”,这就是“链表”名称的由来。 如果结点的引用域只存储该结点直接后继结点的存储地址,则该链表叫单链表(Singly Linked List)。把该引用域叫 next。单链表结点的结构如图所示,图中 data 表示结点的数 据域。
data = val; next = p; }
//构造器
public DbNode(DbNode<T> p) {
next = p; }
//构造器 public DbNode(T val) { data = val; next = null; }

数据结构线性表

数据结构线性表

数据结构---线性表线性表代码主要参考严蔚敏《数据结构(c语言版)》,有部分改动线性表的定义定义•线性表是具有相同的数据类型的n(n >= 0)个数据元素的有限序列,当n=0时线性表为一个空表•用L表示线性表则L = (a1,a2,a3,…,ano a1为表头元素,an为表尾元素o a1无直接前驱,an无直接后继特点•表中元素个数有限•表中元素具有逻辑上的顺序,表中元素有先后次序•表中元素都是数据元素•表中元素的数据类型都相同,每个元素占的空间大小一致要点数据项、数据元素、线性表的关系线性表由若干个数据元素组成,而数据元素又由若干个数据项组成,数据项是数据的不可分割的最小单位。

其中姓名,学号等就是数据项线性表的顺序表示顺序表的定义顺序表是指用一组地址连续的存储单元依次存储信息表中的数据元素,从而使得逻辑相邻的两个元素在物理位置上也相邻预先定义(为了代码可以运行)#define True 1#define False 0#define OK 1#define ERROR 0#define INFEASIBLE -1#define OVERFLOW -2typedef int Status;第n个元素的内存地址表示为LOC(A) + (n-1)*sizeof(ElemType)假定线性表的元素类型为ElemType,则线性表的顺序存储类型描述为typedef int ElemType ;#define MaxSize 50typedef struct{ElemType data[MaxSize];int length;}SqList;一维数组可以是静态分配的,也可以是动态分配的。

静态分配后大小和空间都固定了,下面使用动态分配的形式typedef int ElemType ;#define InitSize 100 //表长度的初始大小定义#define ListIncreasement 10 //线性表存储空间的分配增量typedef struct{ElemType *data;int MaxSize,length;}SeqList;顺序表的初始化顺序表的初始化,&是C++的引用,可以使用指针代替Status InitList(SeqList &L){L.data = (ElemType *) malloc(InitSize * sizeof(ElemType));if(! L.data) exit(OVERFLOW);//存储分配失败L.length = 0;L.MaxSize = InitSize;return OK;}顺序表的插入在顺序表L的第i(1<= i <= L.length +1)个位置插入新元素e,需要将第n 个至第i (共n-i+1)个元素向后移动一个位置【最后一个到倒数第n-i+i个元素向后移动一位】。

2013年-数据结构-复习题

2013年-数据结构-复习题

第一部分:数据结构——线性结构(顺序表、链表、栈、队列、数组、串)考点:1、时间复杂度2、数据的逻辑结构与存储结构相关知识——分类、与存储结构之间的关系3、顺序表的知识——特点4、链表的知识——编程求单链表中结点的个数、插入、删除。

5、栈与队列知识——特点、循环队列、基本术语、链队列6、数组与矩阵——求元素的地址、稀疏矩阵行优先存储:下标从1开始:Loc(A i,j) = Loc(A1,1)+[(i-1)*n+j-1]*b下标从0开始:Loc(A i,j) = Loc(A0,0)+(i*n+j)*b 列优先存储:下标从1开始:Loc(A i,j) = Loc(A1,1)+[(j-1)*m+i-1]*b下标从0开始:Loc(A i,j) = Loc(A0,0)+(j*m+i)*b1. 设顺序线性表中有n个数据元素,则第i个位置上插入一个数据元素需要移动表中___________个数据元素;删除第i个位置上的数据元素需要移动表中___________个元素。

2.数据的逻辑结构通常有集合、线性结构、_________ 和 _________ 四类结构。

3.若进栈序列为a、b、c ,且进栈和出栈可以穿插进行,则可能出现_________个不同的出栈序列。

4.在栈结构中,允许插入的一端称为 _________;在队列结构中,允许删除的一端称为 _________。

5. 下列程序段的时间复杂度为_____________s=0;for(i=1;i<n;i++)for(j=1;j<n;j++)s+=i*j;6. 假设某个带头结点的单链表的头指针为head,则判定该表为空表的条件()A、head= =NULLB、head->next= =NULLC、head!=NULLD、head->next= =head7. 栈是一种操作受限的线性结构,其操作的主要特点是()A、先进先出B、后进先出C、进优于出D、出优于进8. 假设以数组A[n]存放循环队列的元素,其头、尾指针分别为front和rear。

数据结构标准

数据结构标准

数据结构标准一、线性结构线性结构是最基本的数据结构,它包括数组、链表、栈和队列等。

1.1 数组数组是一种有序的线性结构,它包含固定大小的元素,并且每个元素都有一个对应的索引。

数组适用于存储相同类型的元素,可以进行高效的随机访问。

1.2 链表链表是一种由节点组成的数据结构,每个节点包含数据和指向下一个节点的指针。

链表适用于存储动态大小的数据,插入和删除操作比较方便。

1.3 栈栈是一种后进先出(LIFO)的数据结构,它适用于存储程序中的调用关系、操作顺序等。

栈只允许在一端进行插入和删除操作。

1.4 队列队列是一种先进先出(FIFO)的数据结构,它适用于存储程序中的任务、消息等。

队列允许在一端进行插入操作,在另一端进行删除操作。

二、树形结构树形结构是一种分层次的数据结构,它包括二叉树、多叉树、森林等。

2.1 二叉树二叉树是一种特殊的树形结构,每个节点最多有两个子节点。

二叉树适用于存储层次关系比较明显的数据,如表达式树、二叉搜索树等。

2.2 多叉树多叉树是一种每个节点可以有多于两个子节点的树形结构。

多叉树适用于存储层次关系复杂的数据,如XML文档、HTML文档等。

2.3 森林森林是一种由多个不相交的树组成的集合。

森林适用于存储多个不相交的层次关系比较明显的数据集。

三、图状结构图状结构是一种非线性的数据结构,它包括有向图、无向图、加权图等。

3.1 有向图有向图是一种由节点和有向边组成的数据结构,每个节点可以与任意其他节点相连通。

有向图适用于存储表示依赖关系的数据,如程序的控制流图等。

3.2 无向图无向图是一种由节点和无向边组成的数据结构,每个节点可以与任意其他节点相连通。

无向图适用于存储表示合作关系的数据,如社交网络等。

数据结构之线性结构和非线性结构

数据结构之线性结构和非线性结构

数据结构之线性结构和非线性结构在计算机科学的世界里,数据结构就像是建筑物的架构,为数据的存储和操作提供了基础。

其中,线性结构和非线性结构是两种重要的分类。

线性结构,顾名思义,数据元素之间存在着一种线性的关系。

就好像是排成一列的士兵,一个接一个,顺序明确。

常见的线性结构有数组、链表和栈、队列等。

数组是一种最简单也是最常见的线性结构。

想象一下,它就像是一排整齐的盒子,每个盒子都有一个固定的位置,通过索引就能快速找到对应的元素。

数组的优点是访问元素速度快,只要知道索引,就能瞬间获取对应的值。

但它也有缺点,比如插入和删除元素比较麻烦,因为要移动大量的元素来腾出或填补位置。

链表则与数组不同。

它就像是一串珠子,每个珠子(节点)不仅包含数据,还包含指向下一个节点的链接。

链表在插入和删除元素时非常方便,只需要修改相邻节点的链接就行,无需大量移动元素。

但链表的访问速度相对较慢,要找到特定的元素,需要从头节点开始逐个遍历。

栈是一种特殊的线性结构,它遵循着“后进先出”的原则。

可以把栈想象成一个只有一个开口的桶,最后放进去的东西会最先被拿出来。

在程序中,函数调用的栈帧就是用栈来实现的。

队列则是“先进先出”,就像排队买票,先来的先买到票离开。

在计算机中,打印任务的排队、消息的传递等都可以用队列来实现。

说完线性结构,再来看非线性结构。

非线性结构的数据元素之间不是简单的线性关系,而是更为复杂的网状或层次关系。

树就是一种典型的非线性结构。

比如二叉树,每个节点最多有两个子节点。

二叉查找树在查找、插入和删除操作上都有很高的效率。

还有平衡二叉树、红黑树等,它们通过一些规则保持树的平衡,进一步提高了操作性能。

图则是更加复杂的非线性结构。

它由顶点和边组成,可以表示各种复杂的关系。

比如社交网络中人与人的关系、地图中城市之间的道路连接等。

线性结构和非线性结构在实际应用中各有其优势。

在选择使用哪种数据结构时,需要根据具体的需求来决定。

如果需要频繁地随机访问元素,数组可能是更好的选择;如果需要频繁地插入和删除元素,链表可能更合适。

数据结构(C语言版) 线性表 详细举例介绍

数据结构(C语言版) 线性表 详细举例介绍
// La中不存在和 e 相同的数据元素,则插入之
}
} // union
O(ListLength2(Lb))
算法2.1’’
试改变结构, 选用有序表表示集合。
有序表: 其数据元素依值从小 到大(非递减)有序排列的 线性表。
例如: (2,3,3,5,6,6,6,8,12)
void purge(List &La, List Lb) {
(求数据元素的后继)
初始条件: 线性表L已存在。
若cur_e是L的元素,但不是 操作结果:
最后一个,则用next_e返回它 的后继,否则操作失败, next_e无定义。
GetElem( L, i, &e ) (求线性表中某个数据元素)
线性表L已存在, 初始条件: 且 1≤i≤LengthList(L)
算法2.1’’
InitList(LA); La_len = ListLength(La); Lb_len =ListLength(Lb); // 求线性表的长度
for (i = 1; i <= Lb_len; i++) { GetElem(Lb, i, e);
// 取Lb中第i个数据元素赋给e
if (ListEmpty(La) || !equal (en, e)) { ListInsert(La, ++La_len, e); 算法2.1’ en = e;
} // La中不存在和 e 相同的数据元素,则插入之
}
}
O(ListLength(Lb))
例2-2 (教材P.20)
归并两个“其数据元素按值非递减有 序排列”的线性表 LA 和 LB,求得线性 表 LC 也具有同样特性。

数据结构导论 第2章 线性表

数据结构导论 第2章 线性表
线性表(linear list) 第二章 线性表
线性表是一种线性结构,线性结构的特点是数据元 素之间是一种线性关系,数据元素“一个接一个的 排列”。 线性结构是n(n>=0)个结点的有穷序列。对于 n>0的线性结构表示成: (a1,a2,… ai-1,ai,ai+1,…an) a1称为起始结点 an称为终端结点 起始结点, 终端结点; 起始结点 终端结点 ai-1 称为 ai 的直接前趋 i+1 称为 ai 的直接后继 直接前趋,a 直接后继。 直接前趋 直接后继
4.查找(定位) locate(L,x): .查找(定位) :
依次将顺序表L中的每个元素与给定的值x进行比 较。若找到则返回其序号(下标+1),否则返回0。 int locate (sqlist L, datatype x) { int i; for ( i=0; i<st; i++) if (L.data[i]==x) return (i+1); return(0); }
void insert (sqlist *L, datatype x, int i ) { if (i<1 || i>L->last+1) error (“插入位置错误”); else if (L->last==maxsize) error (“溢出”); else { for (j=L->last-1; j>=i-1; j--) //往后移动元素 //往后移动元素 L->data[j+1]=L->data[j]; L->data[i-1]=x; //插入x L->last++; //修改表长 } }
常见的线性表的基本运算有以下几个: 常见的线性表的基本运算有以下几个:

数据结构第2章线性表A

数据结构第2章线性表A
15
在线性表的第i个位臵前插入一个元素的示意图如下:
1 2 3 4 插入25 5 12 1
12
13 21
13
21 24 28 30 42 77
2
3 4 5 6 7 8
24
25
6
7 8
28
30 42 77
9
16
3)删除
删除线性表的第i个位臵上的元素
实现步骤: 将第i+1 至第n 位的元素向前移动一个位臵; 表长减1。 注意:事先需要判断,删除位臵i 是否合法? 应当符合条件:1≤i≤n 或 i=[1, n] 核心语句: for ( j=i+1; j<=n; j++ )
18
2.2.3 顺序表的运算效率分析
时间效率分析:
算法时间主要耗费在移动元素的操作上,因此 计算时间复杂度的基本操作(最深层语句频度) T(n)= O (移动元素次数) 而移动元素的个数取决于插入或删除元素的位臵.

讨论1:若在长度为 n 的线性表的第 i 位前 插入一个元素, 则向后移动元素的次数f(n)为: f(n) = n – i + 1
例2 分析学生情况登记表是什么结构。
学号 姓名 性别 年龄 班级
0406010402
0406010405 0406010406 0406010410 0406010413 :
陈杰
邓博 管杰 黄腾达 李荣智 : : :
2004级计软04-1班
2004级计软04-1班 2004级计软04-1班 2004级计软04-1班 2004级计软04-1班 :
InitList( &L ); DestoryList( &L ); //建空表,初始化 //撤销表,释放内存

数据结构之线性表详细解答

数据结构之线性表详细解答

二章线性表线性表是最简单、最基本、也是最常用的一种线性结构。

它有两种存储方法:顺序存储和链式存储,它的主要基本操作是插入、删除和检索等。

2.1 线性表的逻辑结构2.1.1 线性表的定义线性表是一种线性结构。

线性结构的特点是数据元素之间是一种线性关系,数据元素“一个接一个的排列”。

在一个线性表中数据元素的类型是相同的,或者说线性表是由同一类型的数据元素构成的线性结构。

在实际问题中线性表的例子是很多的,如学生情况信息表是一个线性表:表中数据元素的类型为学生类型; 一个字符串也是一个线性表:表中数据元素的类型为字符型,等等。

综上所述,线性表定义如下:线性表是具有相同数据类型的n(n>=0)个数据元素的有限序列,通常记为:(a1,a2,… a i-1,a i,a i+1,…a n)其中n为表长,n=0 时称为空表。

表中相邻元素之间存在着顺序关系。

将a i-1 称为a i 的直接前趋,a i+1 称为a i 的直接后继。

就是说:对于a i,当i=2,...,n 时,有且仅有一个直接前趋a i-1.,当i=1,2,...,n-1 时,有且仅有一个直接后继a i+1,而a1 是表中第一个元素,它没有前趋,a n 是最后一个元素无后继。

需要说明的是:a i为序号为i 的数据元素(i=1,2,…,n),通常我们将它的数据类型抽象为datatype,datatype根据具体问题而定,如在学生情况信息表中,它是用户自定义的学生类型; 在字符串中,它是字符型; 等等。

2.1.2 线性表的基本操作在第一章中提到,数据结构的运算是定义在逻辑结构层次上的,而运算的具体实现是建立在存储结构上的,因此下面定义的线性表的基本运算作为逻辑结构的一部分,每一个操作的具体实现只有在确定了线性表的存储结构之后才能完成。

线性表上的基本操作有:⑴线性表初始化:Init_List(L)初始条件:表L不存在操作结果:构造一个空的线性表⑵求线性表的长度:Length_List(L)初始条件:表L存在操作结果:返回线性表中的所含元素的个数⑶取表元:Get_List(L,i)初始条件:表L存在且1<=i<=Length_List(L)操作结果:返回线性表L中的第i个元素的值或地址⑷按值查找:Locate_List(L,x),x是给定的一个数据元素。

数据结构类型

数据结构类型

数据结构类型数据的逻辑结构:数据的逻辑结构指元素之间的逻辑关系(和现实⽆关)。

分类⼀:线性结构和⾮线性结构 线性结构:有且只有⼀个开始结点和⼀个终端结点,并且所有结点都最多只有⼀个直接前驱和⼀个直接后继。

线性表就是⼀个典型的线性结构,它有四个基本特征: 1.集合中必存在唯⼀的⼀个"第⼀个元素"; 2.集合中必存在唯⼀的⼀个"最后的元素"; 3.除最后元素之外,其它数据元素均有唯⼀的"直接后继"; 4.除第⼀个元素之外,其它数据元素均有唯⼀的"直接前驱"。

⽣活中的案例:冰糖葫芦、排队上地铁⾮线性结构: 相对应于线性结构,⾮线性结构的逻辑特征是⼀个结点元素可能对应多个直接前驱和多个直接后继。

常见的⾮线性结构有: 树(⼆叉树等),图(⽹等)。

树:⼀个结点可以对应多个直接后继,但每个结点只能对应⼀个直接前驱(⼀对多) 图(⽹):⼀个结点可以对应多个直接后继和直接前驱(多对多) 树:⽣活案例 单位组织架构、族谱技术案例:⽂件系统图:⽣活案例 交通线路图、地铁线路图分类2:集合结构、线性结构、树状结构、⽹络结构 逻辑结构有四种基本类型:集合结构、线性结构、树状结构和⽹络结构。

 表和树是最常⽤的两种⾼效数据结构,许多⾼效的算法能够⽤这两种数据结构来设计实现。

1.集合结构: 就是数学中所学的集合,集合中的元素有三个特征: 1).确定性(集合中的元素必须是确定的) 2).唯⼀性(集合中的元素互不相同。

例如:集合A={1,a},则a不能等于1) 3).⽆序性(集合中的元素没有先后之分。

例如:集合{3,4,5}和{3,5,4}算作同⼀个集合) 该结构的数据元素之间的关系是"属于同⼀个集合",此外⽆其他关系。

 因为集合中元素关系很弱,数据结构中不对该结构进⾏研究。

2.线性结构: 数据结构中线性结构指的是数据元素之间存在着"⼀对⼀"的线性关系的数据结构。

数据结构线性表ppt课件

数据结构线性表ppt课件
03
2. 创建两个多项式对象,并初始化它们的系数和指 数。
多项式相加问题
01 3. 遍历两个多项式对象的线性表,将相同指数的 系数相加。
02 4. 创建新的线性表存储结果多项式的系数和指数 。
03
5. 返回结果多项式对象。
约瑟夫环问题
问题描述
n个人围成一圈,从第一个人开始报 数,每次数到m的人出列,然后从下 一个人开始继续报数,直到所有人都 出列为止。求每次出列的人的序号。
03
线性表基本操作
插入操作
在指定位置插入一 个元素。
查找操作
查找指定元素的位 置。
初始化操作
建立一个空的线性 表。
删除操作
删除指定位置的元 素。
遍历操作
访问线性表中的每 个元素。
02
顺序存储结构及其实现
顺序存储结构原理
顺序存储定义
用一段地址连续的存储单元依次 存储线性表的数据元素。
存储方式
逻辑上相邻的元素,其物理存储 位置也相邻。
...,an组成的有序序列。
性质
集合中必存在唯一的一个“第一元素 ”。
集合中必存在唯一的一个“最后元素 ”。
除最后元素之外,均有唯一的后继。
除第一元素之外,均有唯一的前驱。
线性表与数组关系
01
数组是线性表的一种表现和实现形式。
02
线性表是逻辑结构,而数组是存储结构。
任何一种逻辑结构都可以用多种存储结构表示。
顺序表基本操作实现
初始化操作
创建一个空表,分配存储空间。
插入操作
在指定位置插入一个元素,需移动插入位置后的所有元素。
删除操作
删除指定位置的元素,需移动删除位置后的所有元素。

数据结构——线性表(顺序实现)

数据结构——线性表(顺序实现)

数据结构——线性表(顺序实现) 好好学习基础知识,出⼈头地就靠它了,内外兼修。

(好吧,我现在内外都不⾏)写这篇⽂章的⽬的就是为了,巩固刚学完的线性表,个⼈能⼒有限,若有不当之处,望指出。

线性表 好了,扯完了,说正事: 1、定义 线性表是⼀种及其常⽤的并且最简单的⼀种数据结构。

简单来说,线性表就是集合⾥的元素的有限排列。

(在这⾥我把集合定义为具有相同属性的元素,会有些狭义) 在线性表中数据元素之间的关系是⼀对⼀的关系,即除了第⼀个和最后⼀个数据元素之外,其它数据元素都是⾸尾相接的(注意,这句话只适⽤⼤部分线性表,⽽不是全部。

⽐如,循环链表逻辑层次上也是⼀种线性表(存储层次上属于链式存储),但是把最后⼀个数据元素的尾指针指向了⾸位结点)[] 怎么说呢,毕竟数据结构毕竟是逻辑结构,逻辑上符合线性结构的特征即可,存储结构能实现就⾏。

线性表的很重要!很重要!很重要!后⾯的栈,队列,串等都是基于线性表的基础上实现的,所以说⼀定要学好线性表 2、线性表的特点: 对于任意的的⾮空线性表或者线性结构有: 1、存在唯⼀⼀个被称为 ”第⼀个“的元素 2、存在唯⼀⼀个被称为 ”最后⼀个“的元素 3、出第⼀个元素之外,每⼀个元素都存在⼀个后继 4、除最后⼀个元素之外,每⼀个元素都存在⼀个前驱 3、基本操作 1、Create(*L)创建空表 2、InitEmpty(*L)初始化 3、getLength(*L)获取长度 4、Insert(*L)插⼊元素 5、Remove(*L)移除元素 6、IsEmpty(*L)空表检测 7、IsFulled(*L)表满检测(顺序表常⽤,链式表基本不⽤) 8、Delete(*L)删除表 9、getElemt(*L)获取元素 10、Traverse(*L)遍历输出所有元素 11、Clear(*L)清除所有元素 4 、实现 好了最⿇烦的事情开始了,数据结构在计算机上的的映射。

众所周知,线性表有两种实现⽅法,⼀种是顺序表,另⼀种是链式表,这两种结构实现最⼤的不同在于前者逻辑关系⽆需存储空间,⽽后者则需要⽤额外的空间(顺便记录⼀下,指针⼤⼩只由环境有关(严格意义上说和CPU的位数有关)本篇只实现顺序结构)。

数据结构(第二章 线性表)

数据结构(第二章 线性表)

2.2 线性表的顺序存储和实现
顺序表-顺序表定义

由上可知,数据的存储逻辑位置由数组的下标决定。 所以相邻的元素之间地址的计算公式为(假设每个数 据元素占有d个存储单元): LOC(ai)=LOC(ai-1)+d 对线性表的所有数据元素,假设已知第一个数据元 素a0的地址为LOC(a0) ,每个结点占有d个存储 单元, 则第i个数据元素ai的地址为: LOC(ai)=LOC(a0)+i*d 线性表的第一个数据元素的位置通常称做起始位置 或基地址。 在使用一维数组时,数组的下标起始位置根据给定 的问题确定,或者根据实际的高级语言的规定确定。
2.1 线性表抽象数据类型
线性表的分类
顺序存储结构 (元素连续存储、 随机存取结构) 线性表 ADT 链式存储结构 (元素分散存储) 继承 顺序表类 排序顺序表类 继承 单链表类 循环单链表 双链表 继承 排序循环双链表类 排序单链表类

单链表
双链表

循环双链表类
线性表的存储结构
2.2 线性表的顺序存储和实现
线性表的基本操作 求长度:求线性表的数据元素个数。 访问:对线性表中指定位置的数据元素进行存取、替 换等操作。 插入:在线性表指定位置上,插入一个新的数据元素, 插入后仍为一个线性表。 删除:删除线性表指定位置的数据元素,同时保证更 改后的线性表仍然具有线性表的连续性。 复制:重新复制一个线性表。 合并:将两个或两个以上的线性表合并起来,形成一 个新的线性表。 查找:在线性表中查找满足某种条件的数据元素。 排序:对线性表中的数据元素按关键字值,以递增或 递减的次序进行排列。 遍历:按次序访问线性表中的所有数据元素,并且每 个数据元素恰好访问一次。

如何区分数据结构中的线性结构与非线性结构?

如何区分数据结构中的线性结构与非线性结构?

如何区分数据结构中的线性结构与⾮线性结构?
数据结构可以分成两⼤类:
线性结构
⾮线性结构
下⾯就来简单聊聊这两种结构,⾄于具体的数据结构,后续咱们慢慢聊。

线性结构
先来说线性结构,怎么理解呢?线性结构的元素之间是⼀个接着⼀个连接,构成线性的形式。

⽐如数组、链表、栈、队列等。

对于数组,元素依次顺序存放,紧挨着,是⼀种顺序存储⽅式。

对于链表,元素之间离散存储,通过指针彼此相连,是⼀种链式存储⽅式。

对于栈跟队列,可以⽤上⾯两种结构:数组或链表来实现。

⾮线性结构
⾮线性结构,也挺好理解。

⾮线性结构的元素可以有多个⼦元素与之关联。

⽐如树结构,⼀个节点可以有左右⼦节点;图结构,每个节点都可以与多个节点关联,从⽽构成复杂⽹络。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

数据结构之线性结构(一,表结构)作者:冲出宇宙时间:2006-10-24修改:2006-11-3转载请注明作者。

作者主要参考了上面的资料(因为wikipedia上不去)和部分较新学术论文(一般来自于acm, IEEE和springer),如果有什么疑问,您可以参考以上资料,我会努力的把重要的论文罗列在文章里面。

本文主要介绍了线性数据结构部分,线性数据的分类来自于wikipedia,见页面:/topic/list-of-data-structures。

1 线性数据结构的分类线性数据结构的分类如下:.表(List).数组(Array).位图(Bitmaps).图片(Images).数字高程模型(Heightfield).动态数组(Dynamic array).平行数组(Parallel array).向量(Vector).集合(Set).链表(Linked list).松散链表(Unrolled linked list).Xor链表(Xor linked list).可变表(VList).联合数组(Associative array).散列表(Hash table).跳跃表(Skip list).栈(Stack).队列(Queue).优先队列(Priority queue).双向队列(Deque).间隙缓冲(Gap buffer)2 表(List)表是一个抽象数据结构(ADT, abstract data type,它表示的是一种接口,而不是实现),它表示的是一个有序实体集合。

但是,表并没有一个确定的接口。

比如,可变的表会包含4种操作:1,建立空表;2,测试表十分为空;3,在前端插入一个数据到表里面去;4,返回一个新表,包含了除了第一个元素(也可能是最后一个元素)以外的其它所有元素。

在现实中,表通常由数组或者链表实现,因为它们都和表具有一些共同点。

通常人们会把表当成是链表的别名。

序列也是表的另外一个名字,它突出了实体之间的顺序关系。

2.1 数组(Array)和数组相关的有向量、表(一维数组实现)、矩阵(二维数组实现),数组是一种最简单的数据结构。

数组包含了一系列的数据元素,而且这些元素一般都是同样的大小和类型。

数组里面的元素通过索引来访问,一般的说,索引是一段连续的整数范围,但是,它也可以为任何有序的数值。

数组可以是多维的,比如,2维数组。

3维或者以上的数组很少被采用。

时间复杂度:通过索引访问数组极快(o(1)),但是,从数组里面插入或者删除一个数据的代价很高(o(n)),特别是删除数据可能会造成数组空闲太多,和插入数据造成数组空间不够。

这些可以利用动态数组来解决。

链表虽然插入或者删除数据较快,可是访问其中的元素十分慢(o(n))。

空间复杂度:数组是最不浪费内存的数据结构,比较起来散列表是十分浪费内存的。

数组不占用任何额外的空间(最多增加一个保存数组的大小,4字节)。

程序:大部分程序都内置数组类型。

2.1.1 位图(Bitmap)位图其实是一个数组,数组的每个元素都是布尔值(0/1)。

常常使用字节数组来表示位图,因为每个字节可以表示8个位图的元素。

位图最常用在空间处理上,比如,磁盘分配。

根据位图的个性,所有用来表示是和否的地方都可以使用它。

因为一个字节的位图可以表示8个是和否,所以,它也常常用来压缩数据。

不过,访问一位比访问一个字节会慢很多,访问一个字节比访问一个int会慢很多(如果32位机器)。

2.1.1.1 图片(Images)图片也叫数字图片。

图片是一个2维结构,每个元素对应于图片上的某点。

每个元素的大小根据其要显示的效果而变化,主要有1位,8位,16位,24位,32位几种。

根据显示色彩的不同,一般可以分为黑白、灰度、彩色(8位,16位,24位,32位)、抖动色这几种。

一般的图片都由很多像素组成,所以,一个图片占用的空间十分大。

一般情况下,压缩是必须的。

最常见的几种压缩格式为:gif(lzw压缩)、png(未知)、jpg(DCT压缩)、jpg2000(小波压缩)。

2.1.1.2 数字高程模型(Heightfield 也叫:Digital Elevation Model, or DEM)DEM也是一个位图,只是,它每个点表示的意思是高度。

上图是根据dem图还原出来的火星地图。

下图是一个加上了色彩的DEM 图。

2.1.2 动态数组(Dynamic Array)它同时的名字还有:可增数组(growable array), 可变长数组(resizable array), 动态表(dynamic table), 数组表(array list)。

它是一种能够自动调整自己大小的数组。

当加入一个新数据时,如果动态数组没有空间了,它会申请一个新的空间,然后把旧数据全部拷贝过去,释放旧空间(有些动态数组的实现并不会拷贝旧数据过去,也不会释放旧空间)。

一般的时候,新分配的空间大小都是原来空间大小的一个倍数,保证有一部分空间是空闲的。

简单的计算一下,就能发现加入一个数据的平均花销是o(1)。

同样的道理,删除一个数据的时候,如果空闲的空间太多了,动态数组也可能申请一个新空间,然后删除旧空间。

申请新空间时,申请多大的空间是一个值得考虑的问题。

目前来说,一般认为申请的新空间为旧空间的1.4-4倍之间都是合适的,最常见的是2倍。

在浪费空间上面,有人证明了至少需要浪费o(n^1/2)这么多空间才能保证插入和删除都在常数时间内完成。

Andrej Brodnik, Svante Carlsson, Erik D. Demaine, J. Ian Munro, and R obert Sedgewick. Resizable Arrays in Optimal Time and Space (1999). Workshop on Algorithms and Data Structures, pp.37–48动态数组还有很多变形,比如,为了加快删除的速度,可以把开始的数据放到中间(如图):这里,第一个数据放到数组的中间,第i个数据放到(i+n/2)%n的位置。

当删除数据的时候,最多只需要移动n/2次就行了。

当然了,需要保存一个开始的位置和实际的数组长度。

比如,删除掉3,得到:5 6 7 1 2 4 *,删除掉7得到:* 5 6 1 2 4 *。

2.1.3 平行数组(Parallel Array)平行数组最初是为了在不支持记录(对象)的环境下面使用的。

它把一个记录切分成多个基本数组,每个数组的长度一样。

比如,struct Info{int age;char*name;}Info person[2];我们可以使用平行数组表示为:int ages[] = {1,2};char *names[] = {"good","zzp"};平行数组拥有的结构简单,访问速度快速,同时,还能够节省结构可能需要使用的指针(某些语言需要指针,某些不需要。

比如,c语言不需要指针,而j ava语言需要指针)。

但是,它的最大缺点是当记录含有很多域的时候,平行数组将变得极难维护,同时,对它的顺序访问并不会实际问顺序的位置,对基于访问局部性的缓冲策略是一大妨碍。

2.1.4 向量(Vector)向量是一个十分基本的动态数组,它具有和动态数组一样的性质。

2.1.5 集合(Set)集合是包含了一系列的数据,这些数据没有经过排序而且也没有重复的数据。

它比较严格的对应于数学上的集合的概念。

集合必须是有限的,这点和数学上的集合不同。

集合一般来说必须支持以下几种操作:1) 判断一个元素是否在集合里面;2) 对集合的所有元素进行遍历;3) 2个集合之间的交和并操作。

虽然联合数组是通常的建立集合的数据结构,但是,它并不能很好的支持集合之间的交并操作。

2.1.6 链表(Linked list)链表是计算机科学里面最基础的数据结构之一。

它包含一系列的节点,每个节点含有任意多个的域和一个或者两个的指针。

指针可能指向前面一个节点也可能指向后面一个节点。

增加或者删除一个指定节点都是常数时间,但是随机访问一个节点的代价是o(n)。

常用的3种链表为:单链表、双向链表和循环链表。

见图。

单链表是最简单的链表形式,每个节点有一个指针,指向后一个节点。

最后的那个节点的指针指向null。

它访问任何节点都必须从头开始,一步一步的走到待访问的节点。

双向链表是一个复杂一点的结构,它的每个节点包含2个指针,一个指向前一个节点,一个指向后一个节点。

同样,第一个节点的前向指针指向null,最后那个节点的后向指针指向null。

它可以从头遍历也可以从尾遍历。

循环链表把第一个节点和最后一个节点链接了起来。

它可以在单向链表或者双向链表的基础上构建。

第一个节点的前向指针指向最后的那个节点,而最后那个节点的后向指针指向第一个节点。

哨兵节点(Sentinel Nodes)是一个额外的未使用的节点,它常常在链表的开头或者结尾。

它用来加快或者简化某些计算的过程。

2.1.6.1 松散链表(unrolled linked list)链表的最大问题是访问非聚集(即连续的访问并不是访问连续的内存空间),松散链表的主要目的是为了解决这个问题(从而显著的提高缓冲性能)。

松散链表改进了普通链表的结构,现在每个节点可以包含多个数据。

每个节点包含多个元素。

其基本结构为:struct Node{Node next;//下一个节点int maxElement;// 节点包含的最大元素个数Array Elements;// 本节点包含的元素个数}链表里面的每个节点对应一个元素,而松散链表每个节点可以包含最多ma xElements个元素。

从其定义可以看出,节点可以包含少于maxElement个元素。

那么,我们需要一个规则来决定如何包含元素到节点里面,同时尽量保证节点的elements数组空间利用率高。

基本的松散链表使用的是1-2规则,也就是说,如果节点里面包含的元素个数将大于可以包含的元素个数,那么,就把这个节点分裂成2个节点,而如果这个节点包含的元素数将小于maxElement/2,就从邻近的节点借一些元素过来,如果邻近的节点在借给它之后,拥有的节点数小于m axElement/2的话,就把这2个节点合并成一个节点。

总之,1-2规则就是保证(只有一个节点例外)每个节点至少空间利用在1/2。

按照这个规律,最常使用的还有2-3规则和3-4规则。

再大一些的规则就十分难以控制了,因为笔者曾经写过3-4规则的B*树,代码的复杂程度让我不敢重新再看一遍了。

至于空间性能方面,每个节点至少有1/2的空间利用率,在平衡的情况下,每个节点的利用率应该是(1+1/2)/2=3/4。

相关文档
最新文档