数据结构实验线性表
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
数据结构实验报告
实验名称:实验一线性表——题目1
学生姓名:王海洋
班级: 2018211107
学号:2018210191
日期: 2019年3月22日
1.实验要求
实验目的:
熟练掌握线性表的基本操作,包括:创建、插入、删除、查找、输出、求长度、合并等运算,以及各类操作在顺序存储结构和链式存储结构上的实现。
实验内容:
根据线性表的抽象数据类型的定义,选择下面任一种链式结构实现线性表,并完成线性表的基本功能。
线性表存储结构(五选一):
1、带头结点的单链表
2、不带头结点的单链表
3、循环链表
4、双链表
5、静态链表
线性表的基本功能:
1、构造:使用头插法、尾插法两种方法
2、插入:要求建立的链表按照关键字从小到大有序
3、删除
4、查找
5、获取链表长度
6、销毁
7、其他:可自行定义
编写测试main()函数测试线性表的正确性。
2.程序分析
2.1 存储结构
链表的具体存储表示为:
①用一组任意的存储单元来存放线性表的结点(这组存储单元既可以是连续的,也可以是不连续的)
② 链表中结点的逻辑次序和物理次序不一定相同。
为了能正确表示结点间的逻辑关系,在存储每个结点值的同时,还必须存储指示其后继结点的地址信息(称为指针)
链表的结点结构
┌──┬──┐
│data│next│
└──┴──┘
data 域--存放结点值的数据域
next 域--存放结点的直接后继的地址(位置)的指针域(链域)
地址 内存单元
1000H
头指针 1020H 1080H 10C0H
2.2 关键算法分析
1、关键算法:
1:头插法
自然语言描述:
a:在堆中建立新结点
b:将a[i]写入到新结点的数据域
c:修改新结点的指针域
d:修改头结点的指针域。
将新结点加入链表中
伪代码描述
a:Node <T> * s=new Node <T>
b:s->data=a[i]
c:s->next=front->next;
d:front->next=s
2:尾插法
自然语言描述:
a:在堆中建立新结点:
b:将a[i]写入到新结点的数据域:
c:将新结点加入到链表中
d:修改修改尾指针
伪代码描述
a:Node <T> * s=new Node <T>
b:s->data=a[i]
c:r->next=s;
d:r=s
3:析构/删除函数
自然语言描述:
a:新建立一个指针,指向头结点
b:判断要释放的结点是否存在,
c:暂时保存要释放的结点
d:移动a中建立的指针
e:释放要释放的指针
伪代码描述
a:Node <T> * p=front
b:while(p)
c:front=p
d:p=p->next
e:delete front
4:按位查找函数
自然语言描述:
a:初始化工作指针p和计数器j,p指向第一个结点,j=1
b:循环以下操作,直到p为空或者j等于1
b1:p指向下一个结点
b2:j加1
c:若p为空,说明第i个元素不存在,抛出异常
d:否则,说明p指向的元素就是所查找的元素,返回元素地址
伪代码描述
a:Node <T> * p=front->next;j=1;
b:while(p&&j!=1)
b1:p=p->next
b2:j++
c:if(!p) throw ”error”
d:return p
5:按位查找函数
自然语言描述:
a:初始化工作指针p和计数器j,p指向第一个结点,j=1
b:循环以下操作,找到这个元素或者p指向最后一个结点 b1:判断p 指向的结点是不是要查找的值,如果是,返回j,否则p指向下一个结点,并且j的值加一
c:如果找到最后一个结点还没有找到要查找的元素,返回查找失败信息
伪代码描述
a:Node <T> * p=front->next;j=1;
b:while(p)
b1: if(p->next==x) return j
p=p->next
j++
c:return “error”
6:插入函数
自然语言描述:
a:在堆中建立新结点
b:将要插入的结点的数据写入到新结点的数据域
c:修改新结点的指针域
d:修改前一个指针的指针域,使其指向新插入的结点的位置
伪代码描述
a:Node <T> * s=new Node <T>;
b:s-data=p->data
c:s->next=p->next
d:p->next=s
e:p->data=x
7:删除函数
自然语言描述:
a:从第一个结点开始,查找要删除的位数i前一个位置i-1的结点
b:设q指向第i个元素
c:将q元素从链表中删除
d:保存q元素的数据
e:释放q元素
伪代码描述
a:q=p->next
b:p->next=q->next
c:x=q->data
d:delete q
8:遍历打印函数
自然语言描述:
a:判断该链表是否为空链表,如果是,报错
b:如果不是空链表,新建立一个temp指针
c:将temp指针指向头结点
d:打印temp指针的data域
e:逐个往后移动temp指针,直到temp指针的指向的指针的next域为空伪代码描述
If front->next==NULL
Throw ”an empty list ”
Node<T>* temp=front->next;
while(temp->next)
{ cout<<temp->data<<" ";
temp=temp->next;
}
9:获取链表长度函数
自然语言描述:
a:判断该链表是否为空链表,如果是,输出长度0
b:如果不是空链表,新建立一个temp指针,初始化整形数n为0
c:将temp指针指向头结点
d:判断temp指针指向的结点的next域是否为空,如果不是,n加一,否则return n e: 使temp指针逐个后移,重复d操作,直到temp指针指向的结点的next域为0,返回n 伪代码描述
int n=0
if ront->next==NULL
n=0;
else
{ Node<T>* temp=front->next;
while(temp->next)
n++;
temp=temp->next;
}
return n;
2、代码详细分析:
(1)从第一个结点开始,查找节点,使它的数据比x大,设p指向该结点:
while (x>p->data) { p=p->next;}
(2)新建一个节点s,把p的数据赋给s:s->data=p->data;
(3)把s加到p后面:s->next=p->next; p->next=s;
(4)p节点的数据用x替换:p->data=x;
示意图如图所示
3、关键算法的时间复杂度:O(1)
3.程序运行结果
程序截图
4.总结
1.调试时出现的问题及解决的方法:
(1)刚开始时用NULL置空最后一个节点的指针域,发现调试时出现NULL未声明的情况。
最后发现用0去置空最后一个节点的指针域,调试成功。
(2)刚开始遍历总是不能完全遍历链表。
最后发现循环语句中两个句子顺序写反,更正顺序后,调试成功。
(3)进行调试时析构函数出现错误,检查发现未对front节点进行赋值更新,更正后调试成功。
(4)进行插入操作时发现总是插入在目标位置的下一个位置,检查发现先得到了目标位置的地址后再进行了插入操作,后修改为得到目标位置的前一个地址。
2.心得体会:
这道题是相对比较基础,目的是实现线性表的基本功能,书上也几乎给出了所有的模板类的定义,但是在自己进行编程时还是出了很多问题。
通过这个实例,我对模板类的定义与使用有了个初步的了解,了解了单链表的基本的操作和函数实现。
以后必须自己动手编,实现理论与实践相结合,提高自己的编程能力。
3.下一步的改进:
这个程序的交互性不强,可以改进的地方应该是可以从外部输入数组而不仅仅是编程者给定。
此外,显示的界面不够友好,有待改善,而且可以增加完善的报错机制。
此外,也希望老师能在课上给出更多的优化指导。
代码:
“List.h”
#include<iostream>
using namespace std;
template<class T>
struct Node
{
T data;
struct Node<T>*next;
};
template<class T>
class list
{
private:
Node<T> *front;
public:
int getlength();//获取链表长度
list();//无参构造函数
Node<T>* get(int i);//查找
void insert(int i, T x);//插入
T Delete(int i);//删除
~list();//析构
list(T a[], int n);//头插法
void taillist(T a[], int n);//尾插法
void printlist();//打印
};
template<class T>
list<T>::list()
{
front = new Node<T>;
front->next = NULL;
}
template<class T>
list<T>::list(T a[], int n)
{
front = new Node<T>;
front->next = NULL;
for (int i = n - 1; i >= 0; i--)
{
Node<T>*s = new Node<T>;
s->data = a[i];
s->next = front->next;
front->next = s;
}
}
template<class T>
void list<T>::taillist(T a[], int n) {
front = new Node<T>;
Node<T>*r = front;
for (int i =0; i<=n-1; i++)
{
Node<T>*s = new Node<T>;
s->data = a[i];
r->next = s;
r = s;
}
r->next = NULL;
}
template<class T>
list<T>::~list()
{
Node<T>*p = front;
while (p)
{
p = p->next;
delete front;
front = p;
}
}
template<class T>
Node<T>* list<T>::get(int i)
{
Node<T>*p = front->next;
int j = 1;
while (p&&j != i)
{
p = p->next;
j++;
}
return p;
}
template<class T>
void list<T>::insert(int i,T x)
Node<T>*p = front;
if (i != 1)
p = get(i-1);
if (p)
{
Node<T>*s = new Node<T>;
s->data = x;
s->next = p->next;
p->next = s;
}
else
throw"插入位置错误"; }
template<class T>
T list<T>::Delete(int i)
{
Node<T>*p = front;
if (i != 1)
p = get(i-1);
Node<T>*q = p->next;
p->next = q->next;
T x = q->data;
delete q;
return x;
}
template<class T>
int list<T>::getlength()
{
int n=0;
if (front->next == NULL)
n=0;
else
{
Node<T>*temp = front;
while (temp->next)
{
n++;
temp = temp->next;
}
}
return n;
template <class T>
void list<T>::printlist()
{
Node<T> * p = front;
p = p->next;
while (p->next != NULL)
{
cout << p->data << endl;
p = p->next;
}
cout << p->data;
}
“源.cpp”
#include"list.h"
int main()
{
const int n = 10;
int a[n] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
list<int> list1(a, n);
cout <<"链表长度为:"<<list1.getlength() << endl;
cout <<"链表内数据为:"<< endl;
list1.printlist();
cout << endl;
list1.insert(1, 0);
cout <<"添加数据后的链表为:"<< endl;
list1.printlist();
cout << endl;
cout <<"第二个结点的地址为:"<< list1.get(2) << endl;
list1.~list();
return 0;
}。