北京邮电大学 数据结构 实验一 带头结点的单链表构造

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

数据结构实验报告
实验名称:实验1——单链表的构造
学生姓名:XXXXNB
班级:XXXX
班内序号:
学号:XXXX
日期:XXXXX
1.实验要求
根据线性表的抽象数据类型的定义,完成带头结点的单链表的基本功能。

单链表的基本功能:
1、构造:使用头插法、尾插法两种方法
2、插入:要求建立的链表按照关键字从小到大有序
3、删除
4、查找
5、获取链表长度
6、销毁
7、其他:可自行定义
编写测试main()函数测试线性表的正确性。

2.程序分
编程完成单链表的一般性功能如单链表的构造:使用头插法、尾插法两种方法插入:要求建立的链表按照关键字从小到大有序,删除,查找,获取链表长度,销毁用《数据结构》中的相关思想结合C++语言基本知识编写一个单链表结构。

本程序为使用方便,几乎不用特殊的命令,只需按提示输入即可,适合更多的用户使用。

2.1 存储结构
单链表的存储结构:
2.2 关键算法分析
1.头插法
自然语言描述:a.在堆中建立新结点
b.将a[i]写入到新结点的数据域
c.修改新结点的指针域
d.修改头结点的指针域,将新结点加入链表中
//在构建之初为了链表的美观性构造,进行了排序
代码描述:
//头插法构造函数
template<class T>
LinkList<T>::LinkList(T a[], int n)
{
for (int i = n - 1; i >= 1; i--)//冒泡排序,对数组进行从小到大排序{
for (int j = 0; j < i; j++)
{
if (a[j]>a[j + 1])
{
T t = a[j + 1];
a[j + 1] = a[j];
a[j] = t;
}
}
}
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];//将a[i]写入新结点的数据域
s->next = front->next;//修改新结点的指针域
front->next = s;//修改头结点的指针域,将新结点加入到链表中}
}
2.尾插法
自然语言描述:a.在堆中建立新结点
b.将a[i]写入到新结点的数据域
c.将新结点加入到链表中
d.修改修改尾指针
代码描述:
//尾插法构造函数
template<class T>
LinkList<T>::LinkList(T a[], int n)
{
front = new Node < T > ;
Node<T>*r = front;//命名一个新变量进行转换
for (int i = 0; i < n; i++)
{
Node<T>*s = new Node < T > ;
s->data = a[i];
r->next = s;
r = s;
}
r->next = NULL;
}
时间复杂度:O(n)
3.析构函数
自然语言描述:a.新建立一个指针,指向头结点
b.移动a中建立的指针
c.逐个释放指针
代码描述:
template<class T>
LinkList<T>::~LinkList()//析构函数,销毁链表{
Node<T> * p = front;
while(p)
{
front = p;
p = p->next;
delete front;
}
}
4.按位查找函数
自然语言描述: a.初始化工作指针p和计数器j,p指向第一个结点,j=1
b.循环以下操作,直到p为空或者j等于1
b1:p指向下一个结点
b2:j加1
c.若p为空,说明第i个元素不存在,抛出异常
d.否则,说明p指向的元素就是所查找的元素,返回元素地址代码描述:
template<class T>
Node<T>* LinkList<T>::Get(int i)//按位查找
{
Node<T> * p = front;
int j=0;
while(p)
{
if(j<i)
{
p = p->next;
j++;
}
else break;
}
if(!p) throw"查找位置非法";
else return p;
}
时间复杂度:O(n)
5.按值查找函数
自然语言描述:a.初始化工作指针p和计数器j,p指向第一个结点,j=1
b.循环以下操作,找到这个元素或者p指向最后一个结点
b1.判断p指向的结点是不是要查找的值,如果是,返回j;
b2.否则p指向下一个结点,并且j的值加一
c.如果找到最后一个结点还没有找到要查找的元素,返回查找失败信息代码描述:
template<class T>
int LinkList<T>::Locate(T x)//按值查找
{
Node<T> * p = front->next;
int j = 1;
while(p)
{
if(p->data == x) return j;
else
{
p = p->next;
j++;
}
}
return -1;
}
时间复杂度:O(n)
6.插入函数
自然语言描述:a.在堆中建立新结点
b.将要插入的结点的数据写入到新结点的数据域
c.修改新结点的指针域
d.修改前一个指针的指针域,使其指向新插入的结点的位置
代码描述:
template<class T>
void LinkList<T>::Insert(int i,T x)//插入函数
{
Node<T> * p = Get(i-1);
if(p)
{
Node<T> * s = new Node<T>;
s->data = x;
s->next = p->next;
p->next = s;
}
else throw"插入位置非法";
}
时间复杂度:O(n)
7.按位删除函数
自然语言描述:a.从第一个结点开始,查找要删除的位数i前一个位置i-1的结点
b.设q指向第i个元素
c.将q元素从链表中删除
d.保存q元素的数据
e.释放q元素
代码描述:
template<class T>
T LinkList<T>::Delete(int i)//删除函数
{
Node<T> *p = Get(i-1);
Node<T> *q = p->next;
T x=q->data;
p->next = q->next;
delete q;
return x;
}
8.遍历打印函数
自然语言描述: a.判断该链表是否为空链表,如果是,报错
b.如果不是空链表,新建立一个temp指针
c.将temp指针指向头结点
d.打印temp指针的data域
e.逐个往后移动temp指针,直到temp指针的指向的指针的next域为空代码描述:
template<class T>
void LinkList<T>::PrintList()//打印链表
{
Node<T> * p = front->next;
while(p)
{
cout<<p->data<<' ';
p = p->next;
}
cout<<endl;
}
9.获取链表长度函数
自然语言描述:a.判断该链表是否为空链表,如果是,输出长度0
b.如果不是空链表,新建立一个temp指针,初始化整形数n为0
c.将temp指针指向头结点
d.判断temp指针指向的结点的next域是否为空,如果不是,n加一,否则return n
e.使temp指针逐个后移,重复d操作,直到temp指针指向的结点的next 域为0,返回n
代码描述:
template<class T>
int LinkList<T>::GetLength()//分析链表长度
{
Node<T> * p = front;
int i=0;
while(p)
{
p = p->next;
i++;
}
return i-1;
}
2.3 其他
异常处理
采用try catch 函数处理异常
如在插入时的异常处理:
template<class T>
void LinkList<T>::Insert(int i, T x)
{
Node<T>*p = front;
if (i != 1) p = Get(i - 1);
try
{
if (p)
{
Node<T>*s = new Node < T > ;
s->data = x;
s->next = p->next;
p->next = s;
}
else throw i;
}
catch (int i)
{
cout << "插入到位置 " << i << " 处" << "为错误位置"<<endl;
}
}
3. 程序运行结果
主函数流程图:
测试截图:
初始化链表,菜单创建
执行功能:
4. 总结
.调试时出现了一些问题如:异常抛出的处理,书中并未很好的提及异常处理,通过查阅资料,选择用try catch 函数对解决。

2.心得体会
了解了单链表的基本的操作函数实现,对链式存储结构有了较好的认识
3.下一步的改进
可以增加完善报错机制,增强程序的健壮性
完整源代码:
//单链表的构造
#include<iostream>
using namespace std;
template<class T>
struct Node
{
T data;//数据域
struct Node<T>*next;//指针域
};
template <class T>
class LinkList
{
public:
LinkList(){ front = new Node <T>; front->next = NULL; }//无参构造函数
LinkList(T a[], int n);//有参构造函数,使用含有n个元素的数组a初始化单链表
~LinkList(); //析构函数,(其在void main 函数最后一句语句之后自动执行,旨在释放栈空间)
void PrintList(); //按次序遍历线性表中的各个数据元素
int GetLength(); //获取线性表的长度
Node <T> * Get(int i); //获取线性表第i个位置上的元素结点地址
int Locate(T x); //查找线性表中值为x的元素,找到后返回其位置
void Insert(int i, T x);//后插,在线性表的第i个位置上插入值为x的新元素
void insert(int i, T x);//前插,在线性表的第i个位置上插入值为x的新元素
T Delete(int i); //删除线性表第i个元素,并将该元素返回
private:
Node <T> * front; //头指针
};
//头插法构造函数
template<class T>
LinkList<T>::LinkList(T a[], int n)
{
for (int i = n - 1; i >= 1; i--)//冒泡排序,对数组进行从小到大排序
{
for (int j = 0; j < i; j++)
{
if (a[j]>a[j + 1])
{
T t = a[j + 1];
a[j + 1] = a[j];
a[j] = t;
}
}
}
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];//将a[i]写入新结点的数据域
s->next = front->next;//修改新结点的指针域
front->next = s;//修改头结点的指针域,将新结点加入到链表中
}
}
//尾插法构造函数
//template<class T>
//LinkList<T>::LinkList(T a[], int n)
//{
// front = new Node < T > ;
// Node<T>*r = front;//命名一个新变量进行转换
// for (int i = 0; i < n; i++)
// {
//Node<T>*s = new Node < T > ;
//s->data = a[i];
//r->next = s;
//r = s;
//}
//r->next = NULL;
//}
template<class T>
void LinkList<T>::PrintList()//遍历线性表元素并打印到屏幕
{
Node<T>*p = front->next;
while (p)
{
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
template<class T>
LinkList<T>::~LinkList()//析构函数
{
Node<T>*p = front;//初始化工作指针P
while (p)//要释放的结点存在
{
front = p;
p = p->next;
delete front;//释放结点
}
}
template<class T>
Node <T> * LinkList<T>::Get(int i)//获取线性表第i个位置上的元素结点地址{
Node<T>*p = front->next;
int k = 1;
while (p && (k != i))
{
p = p->next;
k++;
}
return p;
}
template<class T>
int LinkList<T>::Locate(T x)//按值查找某元素的位置
{
Node<T>*p = front->next;
int k = 1;
while (p&&(p->data != x))
{
p = p->next;
k++;
}
return k;
}
//后插
template<class T>
void LinkList<T>::Insert(int i, T x)
{
Node<T>*p = front;
if (i != 1) p = Get(i - 1);
try
{
if (p)
{
Node<T>*s = new Node < T > ;
s->data = x;
s->next = p->next;
p->next = s;
}
else throw i;
}
catch (int i)
{
cout << "插入到位置 " << i << " 处" << "为错误位置"<<endl;
}
}
template<class T>
T LinkList<T>::Delete(int i)
{
Node<T>*p = front;
if (i != 1) p = Get(i - 1);//若不是在第一个位置删除,获取第i-1个元素的地址try
{
if (p && (p->next))
{
Node<T>*q = p->next;
p->next = q->next;
T x = q->data;
delete q;
return x;
}
else throw i;
}
catch (int i)
{
cout << "删除位置 " << i << " 处" << "为错误位置" << endl;
}
}
template<class T>
int LinkList<T>::GetLength()
{
Node<T>*p = front->next;
int i;
for (i = 0; p != NULL; i++)
{
p = p->next;
}
return i;
}
void main()
{
int m=1;
int a[7] = { 3, 2, 1, 4, 6, 5, 7 };
LinkList<int> list(a, 7);
cout << "排序后的链表为:";
list.PrintList();
cout << "\t\t**************************************************" << endl << "\t\t※※" << endl
<< "\t\t※对该单链表的操作※" << endl
<< "\t\t※※" << endl
<< "\t\t※ 1. 获取线性表的长度※" << endl
<< "\t\t※※" << endl
<< "\t\t※ 2. 查找值为x的元素,并返回其位置※" << endl
<< "\t\t※※" << endl
<< "\t\t※ 3. 在线性表的第i个位置上插入值为x的新元素※" << endl
<< "\t\t※※" << endl
<< "\t\t※ 4. 删除线性表第i个元素,并将该元素返回※" << endl
<< "\t\t※※" << endl
<< "\t\t**************************************************" << endl << endl;
while (m != 0)
{
cout<< "\t\t\t选择你需要的功能:";
int choice;
cin >> choice;//输入需要的功能
switch (choice)
{
case 1:
cout << "线性表的长度为:" << list.GetLength()<<endl;//获取线性表的长度
break;
case 2://查找值为x的元素,并返回其位置
{
cout << "请输入想查找的元素的值:" << endl;
int value;
cin >> value;
int location = list.Locate(value);
cout << "该元素的位置为:" << location << endl;
}
break;
case 3://在线性表的第i个位置上插入值为x的新元素
{
cout << "请输入想插入的位置值:" << endl;
int location_2;//位置值
cin >> location_2;
cout << "请输入想插入的新元素的值" << endl;
int value_1;//元素值
cin >> value_1;
list.Insert(location_2, value_1);
cout << "执行插入操作后的链表为:" << endl;
list.PrintList();
}
break;
case 4:// 删除线性表第i个元素,并将该元素返回
{
cout << "请输入想要删除的元素的位置值:" << endl;
int location_3;
cin >> location_3;
int value_2 = list.Delete(location_3);
cout << "删除的元素值为:" << value_2 << endl;
}
break;
default:
cout << "!!无此功能项" << endl;
break;
}
cout << " ※※※那您是否想继续?继续请输入 1 不想继续请输入 0 ※※※" << endl;
cin >> m;
}
}。

相关文档
最新文档