IME IME30-10BNSZW2S, 在线数据表 - sick-china.data ... · 在线数据表 ime30-10bnszw2s ime 电感式接近传感器
2 线性表 (2)
description
Transcript of 2 线性表 (2)
数据结构 --- 线性表
2 2 线性表线性表(2)(2)
数据结构 --- 线性表
1.了解线性结构的特点2.掌握顺序表的定义、查找、插入和删除 3.掌握链表的定义、查找、插入和删除 4.能够从时间和空间复杂度的角度比较两种
存储结构的不同特点及其适用场合5.应用线性结构解决基本问题6.了解 STL中的 vector,list的基本使
用方法
1.了解线性结构的特点2.掌握顺序表的定义、查找、插入和删除 3.掌握链表的定义、查找、插入和删除 4.能够从时间和空间复杂度的角度比较两种
存储结构的不同特点及其适用场合5.应用线性结构解决基本问题6.了解 STL中的 vector,list的基本使
用方法
教学目标
数据结构 --- 线性表
2.1 线性表的定义
2.2 线性表的顺序表示和实现
2.3 线性表的链式表示和实现
2.4 线性表与 STL(标准模板库)
2.1 线性表的定义
2.2 线性表的顺序表示和实现
2.3 线性表的链式表示和实现
2.4 线性表与 STL(标准模板库)
教学内容
数据结构 --- 线性表
2.3 线性表的链式表示和实现
数据结构 --- 线性表
一、单链表二、结点和单链表的 C++ 语言描述三、线性表的操作在单链表中的实现四、其它形式的链表五、编程实现带头结点的单链表
数据结构 --- 线性表
用一组地址任意的存储单元存放线性表中的数据元素。
一、单链表
以元素 ( 数据元素的存储 )
+ 指针 ( 指示后继元素存储位置 )
= 结点以“结点的序列”表示线性表 称作链表
数据结构 --- 线性表
以线性表中第一个数据元素 的存储地址作为线性表的地址,称作线性表的头指针。
1a
头结点 a1 a2 … ... an ^
头指针头指针
有时为了操作方便,在第一个结点之前虚加一个“头结点”,以指向头结点的指针为链表的头指针。 ( 这样,头指针永不为空 )
空指针线性表为空表时,头结点的指针域为空
数据结构 --- 线性表
struct LinkList{ LNode *head; // 头指针 ( 带头结点 ) //LNode *tail , *cur;// 尾指针 , 当前指针 //int length; // 链表长度 bool Init(); // 初始化 void Clear(); // 清除线性表 void Create(int n); // 建立含 n 个结点的单链表 int Locate(ElemType e); // 查找 bool InsertBefore(int i, ElemType e);// 插入元素 bool Delete(int i); // 删除元素 void Traverse(); // 遍历,并输出内容 bool Empty(); // 判断空表};
二、 线性表链式映像的 C++ 语言描述struct LNode { ElemType data; // 数据域 Lnode *next; // 指针域} ;
数据结构 --- 线性表
ai-1
InsertBefore(i, e) 的实现: 有序对 <ai-1, ai> 改变为 <ai-1, e> 和 <e, ai>
e
aiai-1
因此,在单链表中第 i 个结点之前进行插入的基本操作为 : 找到线性表中第 i-1个结点,然后修改其指向后继的指针。
三、线性表的操作在单链表中的实现
数据结构 --- 线性表
void InsertBefore(int i, int e) {
// 本算法在链表第 i 个结点之前插入新的元素 e
} // InsertBefore算法的时间复杂度为 : O(n)
p = head;
while (p && i>1) { p=p->next; i--; }//找第 i-1个结点if (p==NULL || i <1) return; // i 大于表长或者小于 1 s = new LNode; // 生成新结点s->data = e;
s->next = p->next; p->next = s; // 插入
数据结构 --- 线性表
数据结构 --- 线性表
核心代码:s = new LNode; // 生成新结点s->data = e;
s->next = p->next; p->next = s; // 插入
e
ai-1 aiai-1
s
p
数据结构 --- 线性表
在单链表中删除第 i 个结点的基本操作为 :找到线性表中第 i-1个结点,修改其指向后继的指针。核心代码如下:
ai-1 ai ai+1ai-1
q = p->next; p->next = q->next;
e = q->data; delete q;p q
Delete (i, &e) 的实现 :
有序对 <ai-1, ai> 和 <ai, ai+1> 改变为 <ai-1,
ai+1>
数据结构 --- 线性表
void Delete (int i, int &e) {
// 删除单链表中第 i 个结点
} // Delete算法的时间复杂度为 : O(n)
p = head; j = 0;while (p->next && j < i-1) { p = p->next; ++j; } // 寻找第 i 个结点,并令 p 指向其前趋if (!(p->next) || j > i-1) return; // 删除位置不合理
q = p->next; p->next = q->next; // 删除并释放结点e = q->data; delete q;
数据结构 --- 线性表
数据结构 --- 线性表
Clear( ) 的实现 :
void Clear( ) {
// 将单链表重新置为一个空表 while (head->next) {
p=head->next;
head->next=p->next;
}
} // Clear
delete p;
算法时间复杂度:O(n)
数据结构 --- 线性表
如何从线性表得到单链表?
链表是一个动态的结构,它不需要预先分配空间,因此生成链表的过程是一个结点“逐个插入”的过程。
数据结构 --- 线性表
例如:逆位序输入 n 个数据元素的值, 建立带头结点的单链表。操作步骤:一、建立一个“空表”;二、输入数据元素 an , 建立结点并插入;三、输入数据元素 an-1 , 建立结点并插入;
an
an
an-1
四、依次类推,直至输入 a1 为止。
数据结构 --- 线性表
void Create(int n) { // 逆序输入 n 个数据元素,建立带头结点的单链表
} // Create算法的时间复杂度为 : O(n)
head = new LNode;head->next =NULL; // 先建立一个带头结点的单链表
for (i = n; i > 0; i--) { p = new LNode; cin>>p->data; // 输入元素值 p->next = head->next; head->next = p; // 插入}
数据结构 --- 线性表
回顾 前面例 2.1, 2.2, 2.3 三个例子的算法,看一下当线性表分别以顺序表和链表实现时,它们的时间复杂度为多少?
2-1 两集合用线性表 LA 和 LB 表示,求新集合 A = A B∪ 。 void union(List &La, List Lb)
2-2 非纯集合 B 净化为纯集合 A 。void purge(List &La, List Lb)
2-3 void MergeList(List La, List Lb, List &Lc)
数据结构 --- 线性表
void union(List &La, List Lb) { La_len = ListLength(La); Lb_len =ListLength(Lb); for (i = 1; i <= Lb_len; i++) { GetElem(Lb, i, e); if (!Locate(La, e) InsertBefore (La, ++La_len, e); }//for} // union
控制结构:基本操作:
for 循环GetElem, Locate 和 InsertBefore
当以顺序映像实现抽象数据类型线性表时为 : O( LenA×LenB )
当以链式映像实现抽象数据类型线性表时为 : O( LenA×LenB )
例 2-1
算法时间复杂度算法时间复杂度
数据结构 --- 线性表
void purge(List &La, List Lb) { // Lb 元素有序 InitList(LA); La_len = ListLength(La); Lb_len =ListLength(Lb); for (i = 1; i <= Lb_len; i++) { GetElem(Lb, i, e); if (ListEmpty(La) || en!=e) { InsertBefore(La, ++La_len, e); en = e; } }//for} // purge
控制结构:基本操作:
for 循环GetElem 和 InsertBefore
当以顺序映像实现抽象数据类型线性表时为 :O(LenB)当以链式映像实现抽象数据类型线性表时为 :O(LenB2)
例 2-2
算法时间复杂度算法时间复杂度
数据结构 --- 线性表
void MergeList(List La, List Lb, List &Lc) { InitList(Lc); i = j = 1; k = 0; La_len = ListLength(La); Lb_len = ListLength(Lb); while ((i <= La_len) && (j <= Lb_len)) { GetElem(La, i, ai); GetElem(Lb, j, bj); if (ai <= bj) { InsertBefore (Lc, ++k, ai); ++i; } else { InsertBefore (Lc, ++k, bj); ++j; } } … …
控制结构:基本操作:
三个并列的 while 循环GetElem, InsertBefore
当以顺序映像实现抽象数据类型线性表时为 : O( LenA+LenB)当以链式映像实现抽象数据类型线性表时为 : O( (LenA+LenB)2 )
例 2-3
算法时间复杂度算法时间复杂度
数据结构 --- 线性表
用上述定义的单链表实现线性表的操作时,存在的问题:
改进链表的设置:
1.单链表的表长是一个隐含的值;2.在单链表的最后一个元素之后插入元素时,
需遍历整个链表;3.在链表中,元素的“位序”概念淡化,结点
的“位置”概念加强。
1.增加“表长”、“表尾指针” 和 “当前位置的指针” 三个数据域;
2.将基本操作中的“位序 i ” 改变为“指针 p ” 。
数据结构 --- 线性表
void InsAfter(int e ) { // 将数据元素 e 插入在链表当前指针所指结点之后
} // InsAfter
s=new LNode; s->data=e; s->next = curr->next; curr->next = s; if (tail = curr) tail = s; curr = s; // 注意
数据结构 --- 线性表
void DelAfter(int & e ) {
// 删除当前指针所指结点之后的结点 , 操作失败时 e=NULL
} //DelAfter
q = curr->next;curr->next = q->next;if (tail = q) tail = curr;e=q->data; delete q;
数据结构 --- 线性表
void MergeList(LinkList &Lc, LinkList &La,LinkList &Lb) { Lc.Init(); // 初始化 La.curr = La.head->next; Lb.curr = Lb.head->next; // 当前指针指向头结点 while (! La.Empty( ) || !Lb.Empty( )) { // La或 Lb 非空
a=La.GetCurElem(); b=Lb.GetCurElem(); If(a<b)
La.DelAfter( La, e ) ; // 当前指针后移else
Lb.DelAfter( Lb, e ) ;Lc.InsertAfter(e);
} La.destory(); Lb. destory(); // 销毁链表 La 和 Lb} // MergeList
例:归并有序表 La 和 Lb , 生成新有序表 Lc 之后销毁 La 和 Lb
O( LenA+LenB)算法时间复杂度 :算法时间复杂度 :
数据结构 --- 线性表
1. 双向链表四、其它形式的链表
struct DuLNode {
ElemType data; // 数据域DuLNode *prior; // 指向前驱的指针DuLNode *next; // 指向后继的指针
};操作特点:“查询”和单链表相同。“插入”和“删除”需要同时修改两个方向上的指针。
数据结构 --- 线性表
最后一个结点的指针域的指针又指回第一个结点的链表
a1 a2 … ... an
2. 循环链表
和单链表的差别仅在于,判别链表中最后一个结点的条件不再是“后继是否为空”,而是“后继是否为头结点”。
数据结构 --- 线性表
ai-1 ai
e
s->next = p->next; p->next = s;
s->next->prior = s; s->prior = p;
p
s
ai-1 ai
双向链表插入
数据结构 --- 线性表
ai-1
双向链表删除
ai ai+1
p->next = p->next->next;
p->next->prior = p;
p
ai-1
为简单起见,这里没有释放被删除节点的空间
数据结构 --- 线性表
五、编程实现带头结点的单链表struct LinkList{
LNode *head; // 头结点int size; // 链表长度
LinkList(); // 构造函数 , 初始化单链表void create(int a[],int n); // 根据数组 A 中的 n 个元素,建立单链表void clear(); // 释放除头结点外的其他结点bool insert(int i, int e); // 在单链表的第 i个位置前插入 ebool erase(int i); // 在单链表中删除第 i个元素 ,并用 e返回其值void traverse(); // 遍历链表,并输出依序内容LNode* locate(int e); // 查找首个值等于 e的位置 ( 指针 ),否则返回 NULL bool getElem(int i, int &e) // 在单链表中取得第 i个元素void reverse(); // 逆置链表
};
struct LNode{int data;LNode *next;
};
数据结构 --- 线性表
LinkList() { // 构造函数 , 初始化单链表head=new LNode; // 生成头结点head->next=NULL;size=0;
}
void clear(){ // 释放除头结点外的其他结点LNode *p;while(head->next!=NULL){
p=head->next;head->next=p->next;delete p;
}size=0;
}
数据结构 --- 线性表
bool erase(int i) { // 在单链表中删除第 i个元素if(i<1 || i>size) return false;
LNode *p=head;while(p->next!=NULL && i>1){
p=p->next;i--;
}
LNode *q=p->next;p->next=q->next;delete q;size--;return true;
}
数据结构 --- 线性表
bool getElem(int i, int &e){ // 在单链表中取得第 i个元素
if(i<1 || i>size) return false;
LNode *p=head->next;//指向第一个节点
while(p!=NULL && i>1){i--;p=p->next;
}
e=p->data;return true;
}
数据结构 --- 线性表
int main(){LinkList lst;int a[6]={11,12,13,14,15,16};lst.create(a,6); lst.traverse();lst.erase(3); lst.traverse();lst.insert(6,99); lst.traverse();lst.reverse(); lst.traverse();int e; lst.getElem(1,e); cout<<e<<endl;
LNode *p=lst.locate(13);if(p!=NULL) cout<<p->explain<<endl;else cout<<"No found!"<<endl;
lst.clear();lst.create(a,3); lst.traverse();return 0;
}
单链表使用举例单链表使用举例
数据结构 --- 线性表
小结1. 熟练掌握链表中的头结点、头指针和首元结
点的区别。2. 熟练掌握链表的查找、插入和删除算法3. 能够从时间和空间复杂度的角度比较两种存
储结构的不同特点及其适用场合
1. 熟练掌握链表中的头结点、头指针和首元结点的区别。
2. 熟练掌握链表的查找、插入和删除算法3. 能够从时间和空间复杂度的角度比较两种存
储结构的不同特点及其适用场合
数据结构 --- 线性表
课后建议:
HLoj 8801-8808,8812-8824 HDoj 1002, 1715,1753 (大整数加
法)