第 14 章 线性表

30
第 14 第 第第第 第第第第 第第第第第第第第第第第第第第第 C++ 第第第第第第第 第第第第 第第第第第第第第第第第第 C++ 第第 ---- 第第第第第第第第 第第第第第第第第第第第第第第 第第第第第第第第第第第第第 C++ 第第 ---- 第第第第第第第第 第第第第第第第第第第第第第第

Upload: honoria-merritt

Post on 31-Dec-2015

30 views

Category:

Documents


2 download

DESCRIPTION

第 14 章 线性表. 本章目标 介绍线性表的概念及其存储结构的 C++ 定义: 顺序表 和 链表 学习要求 掌握线性表的顺序存储结构 C++ 定义 ---- 即顺序表类的定义 掌握顺序表的 插入函数 和 删除函数 掌握线性表的非顺序存储结构 C++ 定义 ---- 即单链表类的定义 掌握单链表的 插入函数 和 删除函数. 什么是线性表. 日常生活中常见到表格形式的一类数据 列车时刻表 学生成绩表 周名缩写表. 车次. 火车种类. 始发站. 终点站. 始发时间. 到达时间. 140. 特快. 西安. 上海. 20 : 30. 19 : 45. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 第 14 章 线性表

第 14 章 线性表

本章目标介绍线性表的概念及其存储结构的 C++ 定义:顺序表和链表

学习要求掌握线性表的顺序存储结构 C++ 定义 ---- 即顺序表类的定义掌握顺序表的插入函数和删除函数掌握线性表的非顺序存储结构 C++ 定义 ---- 即单链表类的定义掌握单链表的插入函数和删除函数

Page 2: 第 14 章 线性表

什么是线性表

日常生活中常见到表格形式的一类数据

列车时刻表

学生成绩表

周名缩写表  

Page 3: 第 14 章 线性表

车次 火车种类 始发站 终点站 始发时间 到达时间

140 特快 西安 上海 20 : 30 19 : 45

42 特快 西安 北京 17 : 30 7 : 45

361 普快 西安 铜川 9 : 45 13 : 10

…… …… …… …… …… ……

列车时刻表

Page 4: 第 14 章 线性表

学号 姓名 性别 分数

99011001 周敏 女 86

99011002 苏伊诗 女 92

99011003 王苏朋 男 76

…… …… …… ……

学生成绩表

Page 5: 第 14 章 线性表

Sun.

Mon.

Tue.

Wen.

Thu.

Fri.

Sat.

周名缩写表

Page 6: 第 14 章 线性表

1 )表中每一行信息虽然组成的内容不同,但都代表某个明确独立的含义,将表中每一行信息称之为一个数据元素;

2 )每个数据元素在表中的位置固定,除了第一个元素和最后一个元素外,其余元素都有唯一一个前驱元素和唯一一个后继元素;

3 )表中数据元素的个数不相同,有长有短;

4 )大多数表中数据元素会增加或减少,是动态变化的。但也有一些表是固定不变,

将这些表格形式的数据加以抽象,统称为线性表。

上述表格形式的数据具有如下共同特点:

Page 7: 第 14 章 线性表

线性表是由 n ( n≥0 )个数据元素 a 1 , a 2 , a 3 ,…, a n 组成的有限序列,记为:( a 1 , a 2 , a 3 ,…, a n )。 线性表中当前存储的数据元素数目叫做表的长度, n 为表长,当线性表中不包含任何数据元素时,称为空表。显然 n=0 时称为空表。 1 )数据元素 a i ( 1≤i≤n )表示某个具体意义的信息,它可以是一个数,或者是一个字符串,或者是由数和字符串组成的更复杂的信息。但同一个线性表中的所有数据元素必须具有相同的属性(或者说具有相同的数据类型); 2 )若线性表是非空表,则有:(ⅰ)第一个元素 a 1 无前趋元素;(ⅱ)最后一个元素 a n 无后继元素;(ⅲ)其它元素 a i

( 1<i<n )均只有一个直接前趋 a i-1 和一个直接后继 a i+1 。

线性表的定义

Page 8: 第 14 章 线性表

日常生活中线性表的例子

某校 1998—2003 年在校学生人数( 2500 , 3450 , 5000 , 5100 , 5400 , 5500 )是一个线性表,每个数据元素是一个正整数,表长为 6 ; 每个月份英文缩写名称组成一个线性表( JAN ., FEB .,MAR ., APR ., MAY., JUN ., JUL., AUG., SEP ., OCT., NOV., DEC .),表中数据元素是一字符串,表长为 12 ; 屏幕上若干像素(( 50 , 50 , RED),( 100 , 150 ,RED ),( 200 , 200 , BLUE ),( 200 , 250 , GREEN ))亦是一线性表,表中数据元素是由行坐标、列坐标和颜色三个数据项组成的一个像素信息,表长为 4 。 电话号码簿、股票市场里的信息列表、航班时刻表、各种各样的统计报表等等

Page 9: 第 14 章 线性表

对线性表有哪些处理(或操作)呢?

1 )统计线性表里总共有多少个元素。简称求表长,记作 Length( L),2 )获取线性表中某个数据元素的信息。简称取元素,记作Get( L, i ) 3 )置换或修改线性表中某个数据元素的信息。简称置换元素,记作 Replace( L, i , x)4 )在线性表中某个位置上增加一个数据元素。简称插入元素,记作 Insert( L, i , x)5 )删除线性表中某个位置上的一个数据元素。简称删除元素,记作 Delete( L, i )6 )查找某个数据元素是否在线性表中存在。简称查找元素,记作 Locate( L, x)7)求前驱元素,记作 Prior( L, i ),取元素 ai 的直接前驱8 )求后继元素,记作Succ( L, i )9 )对线性表中的数据元素按某个数据项的值递增(或递减)的顺序排列。简称排序,记作Sort(L)。

基本的、常用的处理如下:

Page 10: 第 14 章 线性表

顺序表类

::

i

::

Loc(1)

Loc(1)+C

Loc(1)+C*(j -1)

::

::

存储地址 内存状态 数据元素符号

::

::

i

Page 11: 第 14 章 线性表

顺序表类的定义( 1 ) #include <iostream.h> template <class datatype> class seqlist { private: datatype *data; int maxsize; //maxsize 为线性表的最大可能长度 int last; //last 为线性表中表尾元素的下标 public: seqlist() // 创建 100 个元素的线性表的构造函数 { maxsize=100; data=new datatype[maxsize]; last=-1; //last 为 -1 表示为空表 } seqlist(int sz) // 创建 sz 个元素的线性表的构造函数 { if(sz>0) maxsize=sz; else maxsize=100; data=new datatype[maxsize]; last= -1; //last 为 -1 表示为空表 } bool isempty(){ return last==-1?true:false; } // 判空表 bool isfull(){ return last==maxsize-1; } // 判表满 int length(){ return last+1; } // 求表长

Page 12: 第 14 章 线性表

顺序表类的定义( 2 ) bool getdata(int i,datatype &x) // 取元素 { i--; if (i>=0&&i<=last) { x = data[i]; return true; } else { cout<<” 非法位置读取元素,不能读取! \n”; return false; } } bool get_prior(int i,datatype &x); // 取前驱元素 bool get_succ(int i,datatype &x); // 取后继元素 bool replace(int i,datatype x) // 置换元素 { i--; if (i>=0&&i<=last) { data[i]=x; return true; } else { cout<<” 非法位置修改元素,不能修改! \n”; return false; } } bool insert_data(int i,datatype x); // 插入元素 bool delete_data(int i); // 删除元素 void print_list(); // 显示表中所有元素 int find_data(datatype x); // 查找元素 void sort(); // 排序元素 ~seqlist(){ delete[] data; } // 析构函数};

Page 13: 第 14 章 线性表

顺序表类定义的说明 maxsize 为线性表中数据元素个数最大可能值 last 为线性表中当前实际存入的最后一个数据

元素下标 构造函数有两个重载形式 seqlist ()和 seqli

st(int sz) 。 构造函数创建了 datatype 类型的一维数组,

数据元素在数组里按次序紧密存放 析构函数~ seqlist ()将申请的存储空间释

放, data 指针指向该空间的首地址 数据元素的类型定义为模板是为了定义一个通

用类型的线性表

Page 14: 第 14 章 线性表

struct student_score_table { long num; char name[9]; char sex; float score; }

学生成绩单的定义

Page 15: 第 14 章 线性表

声明几个顺序表类的对象 seqlist <int> la(2000); seqlist <string> lb(2000); seqlist <struct student_score_table

> lc(2000);

以上顺序表类中,还有插入、删除、查找、排序四个函数没有定义函数体,下面讨论插入和删除两个函数的算法实现,查找和排序函数的算法实现放在下一章讨论。

Page 16: 第 14 章 线性表

插入算法的主要步骤和 C 函数如下:

插入前:( a 1 , a 2 ,…, a i-1 , a i ,…, a

n )插入后:( a 1 , a 2 ,…, a i-1 , x , a i ,…,a n )

第 1步 : 判定表不满方可插入;第 2步 : 判定插入位置 i 的合法性;第 3步 : 将第 n至第 i 个元素后移一个存储位置;第 4步 : 将 x插入到 a i-1 之后;第 5步 : 线性表的长度加 1 。

template<class datatype> bool seqlist<datatype>:: insert_data(int i, datatype x){

if ( isfull() ) // 判定表满否{

cout<<”表已满,不能插入! \n”; return false;

}if ( i>=1 && i<=last+2 ) // 判定插入位置 i 的合法性{

// 第 n至第 i 个元素循环后移一个存储位置for (int j=last;j>=i-1;j--)

data[j+1]=data[j]; data[j+1] =x; // x成为线性表中第 i 个元素

last++; // 线性表的长度加 1return true;

}else{

cout<<"插入位置错误,不能插入! \n";return false;

}}

Page 17: 第 14 章 线性表

删除前:( a 1 , a 2 ,…, a i-1 , a i , a i+1 ,…, a n ) 删除后:( a 1 , a 2 ,…, a i-1 , a i+1 ,…, a n ) 第 1步: 判定表不空方可删除;第 2步: 判定删除位置 i值的合法性;第 3步: 将第 i+1至第 n 个元素依次向前移动一个存储位置;第 4步: 将线性表的长度减 1 。

删除算法的主要步骤和 C++ 函数如下:

template<class datatype> bool eqlist<datatype>:: delete_data(int i){

if( isempty() ) // 判定表空否{

cout<<”表已空,不能删除! \n”; return false;

}if ((i>=1)&&(i<=last+1)) // 判定删除位置 i 的合法性{

// 第 i+1至第 n 个元素循环前移一个存储位置for (int j=i-1;j<last;j++)

data[j]=data[j+1]; last--; // 线性表的长度减 1return true;

}else{

cout<<”删除位置错误,不能删除! \n”; return false;

}}

Page 18: 第 14 章 线性表

综合分析线性表的顺序存储结构有五个特点

1 )可以随机存取线性表中每一个元素,存取元素的速度与它在表中的位置无关;2 )不需要额外开辟空间存储关系集合,其逻辑关系隐含在物理存储结构中;3 )插入和删除元素速度较慢,平均地讲每插入或删除一个元素需要移动表长的一半元素;4 )扩充性差,注意顺序表类定义中 MAXSIZE值的确定是件困难的事, MAXSIZE值太大造成存储空间冗余,太小不利于扩充;5 )需要一整块连续空间,但表中元素进进出出,不可能一下子放满,有存储空间空闲不能作为它用。

Page 19: 第 14 章 线性表

线性表的非顺序存储结构 ---- 链表类

设计新的存储结构,改进顺序表的结构:

1、线性表中有多少元素就开辟多少存储空间,不预留空间;

2、元素之间不需要紧挨着存放,元素可以散落在存储器中任何地方;

3、插入和删除都不需要移动大量元素;

Page 20: 第 14 章 线性表

每个元素的存储结构

data next

template<class datatype>

class NODE

{

public:

datatype data; //数据域

NODE<datatype> *next; // 指针域

};

Page 21: 第 14 章 线性表

线性表的非顺序存储结构图

a 1 a 2 a 3 a n

head

指针将线性表中每一个元素有机地连接在一起,指针像链条一样,所以线性表的非顺序存储结构又称链式结构

有了结点类的定义,就可以将整个线性表定义成如下单链表类:

Page 22: 第 14 章 线性表

单链表类( 1 ) template<class datatype> class LIST { private: NODE<datatype> *head; public: LIST(){ head=NULL; } // 构造函数 int length(); // 求表长 bool get_data(int i,datatype &x); // 取元素 bool get_succ(int i,datatype &x); // 取前驱元素 bool get_proc(int i,datatype &x); // 取后继元素 bool replace_data(int i,datatype x); // 置换元素 NODE<datatype> *find_data(int i); // 查找元素 void sort(); // 排序 bool insert_data(datatype data,int i); // 插入元素

Page 23: 第 14 章 线性表

单链表类( 2 ) bool delete_data(int i); // 删除元素 void print_list(); // 打印所有元素 bool insert_rear(datatype data); // 从表尾插入元素 bool insert_head(datatype data); // 从表头插入元素 ~LIST() // 析构函数 { NODE<datatype> *p; while(head) // 将链表中所有元素占用空间释放 { p = head; head = head->next; delete p; } } };

Page 24: 第 14 章 线性表

单链表类的特点1 )线性表中实际有多少元素就存储多少个结点2 )元素存放可以不连续,其物理存放次序与逻

辑次序不一定一致,换句话说, a i-1 可能存放在存储器的下半区,而 a i 可能存放在存储器的上半区

3 )线性表中元素的逻辑次序通过每个结点指针有机地连接来体现

4 )插入和删除不需要大量移动表中元素。

Page 25: 第 14 章 线性表

bi scui t butter cheese eggs grapes j am

head

11

head头指针

grapes 60

::

::

bi scui t 61

cheese 13

eggs 1

::

::

j am NULL

butter 12

存储地址 data)数据域( next)指针域(

1

11

12

13

60

61

Page 26: 第 14 章 线性表

a 1 a i-1 a i a n

head

a 1 a i-1 a i a n

head

data

previ ous current

new node

Newnode = new NODE<datatype>; newnode->data=data;newnode->next=current;previous->next=newnode;

Page 27: 第 14 章 线性表

template<class datatype> bool LIST<datatype>:: insert_data(float data,int i){ NODE<datatype> *current,*previous,*newnode;

int j=1; if((i>length()+1)||(i<0)) // 判定插入位置正确与否

{ cout<<"插入位置不正确,不能插入! \n"; return false;

} newnode=(NODE *)malloc(sizeof(NODE)); // 申请新结点空间 if(newnode==NULL) { cout<<"内存无空间,表已满,不能插入! \n";

return false; } newnode->data=data; newnode->next=NULL; if(i==1) //插入表头,另做处理 { newnode->next=head;

head=newnode; return true;

} current=previous=head; while(current!=NULL&&j<i) // 寻找插入位置 { previous=current;

current=current->next; j++;

}; newnode->next=current; // 修改新结点的指针域 previous->next=newnode; // 修改 ai-1 结点的指针域

return true;}

Page 28: 第 14 章 线性表

a 1 a i-1 a i+1 a n

head

a i

a 1 a i-1 a i+1 a n

head

previ ous current

a i

previous->next=current->next;delete current;

Page 29: 第 14 章 线性表

template<class datatype> bool LIST<datatype>:: delete_data(int i){ NODE<datatype> *current,*previous;

int j=1; if(head==NULL) // 判定是否为空表

{ cout<<"表已空,不能删除。 \n"; return false;

}; if((i<1)||(i>length())) // 判定删除位置是否正确 {

cout<<"删除位置不正确,不能删除! \n"; return false;

} current=previous=head; while(current&&j<i) // 寻找删除位置 {

previous=current; current=current->next; j++;

}; if(head==current) //删除表头元素另做处理 { head=head->next;

delete current; } else { previous->next=current->next; // 修改 ai-1 结点指针域

delete current; // 释放被删结点的存储空间 }

return true; }

Page 30: 第 14 章 线性表

作业

作业 1 :编写测试主函数,测试顺序表的插入和删除函数的正确性作业 2 :编写测试主函数,测试单链表的插入和删除函数的正确性作业 3 :本章习题 1作业 4 :本章习题 2

作业 1 和作业 2提示:粘贴插入和删除函数 编写打印线性表函数 再粘贴测试主函数