数据结构——线性表
来源:互联网 发布:淘宝模特动作大全图片 编辑:程序博客网 时间:2024/04/29 18:11
线性表是数据结构的重要组成部分。数组和链表是线性表的两种常用表现形式,也是数据结构的基础。例如栈比较适用于数组描述,队列比较适用于链表描述,树叶比较适宜于链表描述。数据结构的数组描述和链表描述的基本操作都涉及建立、元素插入和删除操作等。本文主要介绍了线性表的链表形式,并通过丢手帕例子介绍了链表的建立、元素插入和元素删除过程。
1 线性表
由零个或多个数据元素组成的有限序列,元素可以是c++的基本数据类型,也可以是自定义的抽象数据类型。该序列中所含元素的个数称之为线性表的长度。线性表中元素在位置上是有序的。顺序表和链表是线性表的两种重要形式。线性表中基本操作是链表的建立、元素的插入和删除、求线性表的长度和根据元素索引寻找相应元素等。
2 顺序表
我们在学c基础知识的时候就接触了数组,但当时并没有涉及数据结构的概念,其实数组就是一种简单的线性表。虽然我们可以用一个数组存储若干线性表的实例,但通常我们都是用一个数组存储一个线性表实例。
顺序表的存储形式是在内存中占据了连续的内存空间。顺序表有三个属性:存储空间的起始位置、顺序表的最大存储容量和顺序表的当前长度。
3 链表
每个元素用一个单元或结点描述,每个结点有一个用来指向下一个元素的指针。链表是在存储形式上非连续、逻辑形式上连续的数据结构,通过链表中的指针链接次序实现的。配合c++的new和delete操作可以进行动态地插入/删除操作,增加/减小链表的长度。为了代码简洁和高效,有时候我们增加一个头结点放在链表最前面,它的数据域一般没有具体意义,指针域指向第一个节点。头结点不是必须的。
最常用的就是单链表,如果把链表的首尾链接起来,就是循环链表;如果每一个节点既有一个指向后一个元素的指针,又有指向前一个元素的指针,我们称它为双向链表。
下面用一个实例,说明链表的建立、插入和删除等操作。引一个约瑟夫问题,丢手帕问题也是从这个演变来的。在解决这个典型问题中,就用到了链表的知识。据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
先看看下面这个程序吧。
#include<iostream> using namespace std; class list //定义一个类,这里也可以定义为结构体{public: int No; //定义整型成员变量No和list类型的指针变量next list* next;}; int main(){ int number, base; //输入玩丢手帕游戏的总人数和出局数字base cout<<"Pleaseinput the number:"; cin>>number; cout<<endl; cout<<"Pleaseinput the base number:"; cin>>base; cout<<endl; list *p, *head= new list; //定义两个list类型指针,其中head用于单链表完成后的首尾相连 head->No=0; p=head; int i; for(i=1;i<=number;i++) //建立链表,No为编号 { list* node= new list; node->No=i; p->next=node; p=p->next; } p->next=head->next; //链表首尾相连,此时的p仍然在建立的链表的最后一个节点 for(i=1;i<=number;i++) { p=p->next; //第一次循环的时候p从链表最后一个节点到第一个节点,然后输出数据 cout<<p->No<<" "; } cout<<endl; p=head->next; //使p重新指向链表的第一个节点 list*temp= new list; //new一个临时list类型指针,用于后面的删除(出局)操作 while(number>0) {//下面的注释部分为,游戏设定出局数字为3,所以此段代码对于输入的base没影响 /* temp= p->next->next; p->next->next=temp->next; p=temp->next; delete[] temp; number--; */ // for(i=1;i<base;i++) // p=p->next; for(i=1;i<base-1;i++) //找到将要出局的那个人,p指向出局的那个人的前一个人,这里有一个bug,就base不能为1 p=p->next; temp=p->next; //temp就是将要出局的那个人 p->next=temp->next; //越过出局的那个人,将链表链接起来 p=temp->next; //更新p所指的对象,p指向出局那个人的下一个人 delete[] temp; //删除出局的人 number--; //出局后,人数减一 for(i=1;i<=number;i++) //输出还剩下的人 { cout<<p->No<<" "; p=p->next; } cout<<endl; } return0;}
上面这个例子涉及到了链表的建立、插入和删除及元素索引操作,通过这个例子对链表的操作进行综合练习。此例的难点在于通过for循环或者用多个p->next(例如p->next->next;)找到需要出局的人,然后重新连接链表并删除出局的人。关于链表的基础操作,读者可以在网上找些资料进行参考。
4 总结
顺序表和链表都是属于线性表,它们有各自的优点和缺点进行总结。
顺序表要求存储空间是一段连续的内存,在顺序表建立的时候要求确定线性表的容量,所以顺序表的优缺点也显而易见的。在寻找元素的时候可以根据下标快速找到,因此读取元素的时间复杂度为O(1),顺序表适用于索引元素操作;在插入/删除元素时,因为元素是连续存储的,所以要把插入/删除元素之后的元素整体向后/向前移动,因此删除和插入操作的时间复杂度为O(n),顺序表不适用于频繁地删除和插入操作。因为是顺序存储,所以没有类似链表的指向下一个元素的指针,存储当前元素的下一个内存空间就是下一个元素。
优点:
①可以快速存取表中任意位置元素;
②无须为表中元素之间的逻辑关系而增加额外的存储空间。
缺点:
①插入和删除操作移动大量元素;
②造成空间碎片。
链表不要求存储空间是一段连续的内存,也不要求在建立的时候确定线性表的容量,可以动态的增减长度,但必须有一个用来指向下一个元素的指针(单链表)。所以链表在寻找元素的时候必须从头结点开始逐个地向下进行,直到找到该元素或到尾结点。因此读取元素的时间复杂度为O(n),链序表不适用于频繁地索引元素操作;在插入/删除元素时,因为元素根据指针相连的,所以只要移动相应结点的指针,就可以完成插入/删除操作,而不影响其他元素,因此删除和插入操作的时间复杂度为O(1),链表适用于频繁地删除和插入操作。
优点:
①不需要预先分配内存空间,存储空间是动态增长的。
②可以快速地插入和删除元素;
缺点:
①索引元素较顺序表速度慢;
②每个元素需要额外的一个空间存储指向下一个元素的指针。
- 数据结构—线性表
- 数据结构—线性表
- 数据结构—线性表
- 数据结构—线性表
- [数据结构]线性结构——线性表
- 数据结构——线性表
- 数据结构——线性表
- 数据结构——线性表
- 数据结构——线性表
- 数据结构——线性表
- 数据结构——线性表
- 数据结构——线性表
- 数据结构——线性表
- 数据结构——线性表
- 数据结构——线性表
- 数据结构——线性表
- 数据结构——线性表
- 数据结构——线性表
- android典型代码系列(二十八)------通话记录的操作
- linux初学习之正则表达式和通配符
- bootmgfw.efi 任意存放 , 引導不同的 BCD
- WebKit之webIDL详解
- linux ip 命令
- 数据结构——线性表
- Dialog 之Datedialog和TimeDialog
- iOS开发:iOS9.0适配之http修改为https、Bitcode、Scheme白名单等问题
- android典型代码系列(二十九)------短信数据库操作相关
- joj 1089 &&zoj 1060&&poj 1094 以及wa的分析和数据
- 自制吸锡带
- linux文件系统初学
- MVC 过滤器(Filters)
- linux内存管理初学