实验三链表
一、实验目的与要求
1)熟悉链表的类型定义;
2)熟悉链表的基本操作;
3)灵活应用链表解决具体应用问题。
二、实验内容
1)请设计一个单链表的存储结构,并实现单链表中基本运算算法。
编写程序linklist.cpp实现单链表的各种基本运算(假设单链表元素类型ElemType为char),并在此基础上设计主程序exp.cpp完成以下功能。
§ 初始化单链表。
§ 依次插入a,b,c,d,e元素。
§ 输出单链表的元素和长度。
§ 判断单链表是否为空。
§ 输出单链表的第3个元素。
§ 输出元素a的位置。
§ 在第4个元素位置上插入f元素。
§ 查找单链表的第3个元素,如果在,则删除;如果不在,则输出找不到。
§ 释放单链表。
2)请设计一个职工文件emp.dat,每个职工记录包含职工编号(no)、姓名(name)、部门号(depno)和工资数(salary)信息。设计一个单链表的存储结构,完成以下功能:
§ 从emp.dat文件中读取职工记录,并建立一个带头结点的单链表L。
§ 输入一个职工记录。
§ 显示所有职工记录。
§ 按职工编号no对所有职工记录进行递增排序。
§ 按部门号depno对所有职工记录进行递增排序。
§ 按工资数salary,对所有职工记录进行递增排序。
§ 删除指定职工号的职工记录。
§ 删除职工文件中的全部记录。
§ 将单链表中的所有职工记录存储到职工文件emp.dat中。
3)编写程序,实现在带头结点的单链表 L 中删除一个最小值结点的算法。请写出算法思想。
三、实验结果
1)请将调试通过的源代码粘贴在下面。(代码注意书写规范、主要模块要有功能注释)
第一题实验代码:
#include
#include
#include
#include
using namespace std;
typedef char ElemType;
//定义单链表结点类型
typedef struct LNode{
ElemType data;
struct LNode *next;
}LinkList;
//初始化单链表
void InitList(LinkList *&L){
//头节点创建
L=(LinkList *)malloc(sizeof(LinkList));
L->next =NULL;
}
//删除单链表
void DestroyList(LinkList *L){
LinkList *p=L;
LinkList *q=L->next ;
while(q!=NULL){
free(p);
p=q;
q=p->next ;
}
free(p);
}
//判断单链表是否为空
bool ListEmpty(LinkList *L){
if(L->next == NULL){
return 0;//0 代表空
}
else{
return 1;//1 代表非空
}
}
//单链表长度计算
int ListLength(LinkList *L){
LinkList *p=L;
int i=0;
while(p->next !=NULL){
p=p->next ;
i++;
}
return i;
}
//输出单链表
void DispList(LinkList *L){
LinkList *p=L->next ;
while(p->next !=NULL){
cout<data <<" ";
p=p->next ;
}
cout<data<next ;
}
if(p==NULL){
return 0;
}
else{
e=p->data;
return 1;
}
}
//查找元素位置 List + Element
int LocateElem(LinkList *L,ElemType e){
LinkList *p=L;
int j=0;
while(p!=NULL && p->data ==e){
j++;
p=p->next ;
}
if(p==NULL){
return 0;
}
else{
return j+1;
}
}
//插入元素 -> List + Location + Element
int ListInsert(LinkList *L,int i,ElemType e){
LinkList *p=L;
LinkList *s;
int j=0;
while(p!=NULL && jnext ;
}
if(p==NULL){
return 0;
}
else{
s=(LinkList *)malloc(sizeof(LinkList));
s->data =e;
s->next =p->next ;
p->next =s;
return 1;
}
}
//删除元素 -> List + Location + Element
int ListDelete(LinkList *L,int i,ElemType e){
LinkList *p=L;
LinkList *s;
int j=0;
while(p!=NULL && jnext ;
}
if(p==NULL){
return 0;
}
else{
s=p->next ;
if(s==NULL){
return 0;
}
e=s->data ;
p->next =s->next ;
free(s);
return 1;
}
}
int main(){
LinkList *h;
ElemType e;
cout<
第一题输出展示:
第二题实验代码:
#include
#include
#include
#include
using namespace std;
//每个职工记录的基本信息建立
typedef struct w{
int no;//职工编号(no)
char name[10];//姓名(name)
int depno;//部门号(depno)
int salary;//工资数(salary)
struct w* next;
}worker;
//输入一个职工记录
void input(worker *&L){
worker *p=(worker*)malloc(sizeof(worker));
cout<<"请输入该职工的基本信息"<> p->no >> p->name >> p->depno >> p->salary ;
//头插法
p->next=L->next ;
L->next =p;
cout<<"已完成,可输入2进行查询"<next ;
for(p=L->next;p!=NULL;p=p->next ){
cout<<" no:"<no
<<" name:"<name
<<" depno:"<depno
<<" salary:"<salary<next ==NULL){
cout<<"当前链表为空"<next->next;
L->next->next=NULL;
while(q!=NULL){
p=L;
while(p->next !=NULL && q->no >= p->next ->no){
p=p->next ;
}
s=q->next ;
q->next =p->next ;
p->next =q;
q=s;
}
cout<<"已完成,可输入2进行查询"<next==NULL){
cout<<"当前链表为空"<next ->next;
L->next ->next=NULL;
while(q!=NULL){
p=L;
while(p->next !=NULL && q->depno >=p->next ->depno){
p=p->next ;
}
s=q->next ;
q->next =p->next ;
p->next =q;
q=s;
}
cout<<"已完成,可输入2进行查询"<next==NULL){
printf("链表为空\n");
return;
}
q=L->next->next;
L->next->next=NULL;
while(q!=NULL){
p=L;
while(p->next!=NULL && q->salary >= p->next->salary){
p=p->next;
}
s=q->next;
q->next=p->next;
p->next=q;
q=s;
}
cout<<"已完成,可输入2进行查询"<>num;
for(p=L;p->next !=NULL;p=p->next ){
if(p->next ->no==num){
temp=p->next ;
p->next =temp->next;
free(temp);
break;
}
}
cout<<"已完成,可输入2进行查询"<next;
worker *q;
while(p!=NULL){
q=p;
p=p->next;
free(q);
}
L->next=NULL;
cout<<"已完成,可输入2进行查询"<next=NULL;
while(1){
int opt;
book();
cout<<"请输入以上数字进行职工信息操作:";
cin>>opt;
switch(opt){
case 1://输入一个职工记录
input(L);
break;
case 2:
show(L);
break;
case 3:
no_sort(L);
break;
case 4:
depno_sort(L);
break;
case 5:
salary_sort(L);
break;
case 6:
listdelete(L);
break;
case 7:
destroy(L);
break;
case 8:
return 0;
default:
cout<<"输入数字有误,请重新输入"<
第二题输出展示:
操作1:
操作2:
操作3:
操作4:
操作5:
操作6:
操作7:
操作8:
第三题实验代码:
void delminnode(LinkNode *L){
LinkNode *r=L,*p=L->next,*q=p->next,*s=p;//p总是指向最小结点,r总是指向p的前驱结点,q遍历,s指向q的前驱结点
while(q!=NULL){
if(p->data > q->data){
r=s; //p>q时,r指向p
p=q; //p总是指向最小结点
q=q->next; //q向后遍历
s=s->next;
}
else{
q=q->next;
s=s->next;
}
}
r->next = p->next;
free(p); //删除p结点
}
2)请分析你程序中每个功能模块的算法时间复杂度。
第一题:
p从头结点开始遍历,每经过一个非空元素就通过free(p)进行删除,同时重置p为其后继结点q,重置q为q的后继结点。由此可见,时间复杂度为O(n)。
只需要对头结点的后继结点进行判断,因为头结点不存放数据,所以若后继结点非空则链表非空,若后继结点为空则链表为空。由此可见,时间复杂度为O(1)。
通过p遍历链表,计算链表所存储的元素个数,遇到空指针便结束计算。由此可见,时间复杂度为O(n)。
通过p遍历链表,输出链表所存储的每一个元素,遇到空指针便结束输出。由此可见,时间复杂度为O(n)。
本段代码是求指定位置的元素,通过遍历单链表从头结点摸索到指定位置的结点并输出其对应的元素。由此可见,时间复杂度为O(n)。
本段代码是求指定元素的位置,通过遍历单链表从头结点摸索每一个位置的元素是否与已知元素等同,若等同则输出相应的位置。由于初始化计数变量j是从0开始计数的,因此在最后需要进行+1操作。由此可见,时间复杂度为O(n)。
本段代码是在指定位置插入指定元素,通过while循环确定所需要插入的元素的前驱结点,再插入指定元素。由此可见,时间复杂度为O(n)。
本段代码是在指定位置删除元素,思路与在指定位置插入指定元素类似,主要是通过while循环确定所需要删除的元素的。由此可见,时间复杂度为O(n)。
第二题:
本段代码是直接插入一打数据,不需要遍历单链表。由此可见,时间复杂度为O(1)。
本段代码是通过从头结点遍历单链表,找到每一个结点所存储的数据并输出。由此可见,时间复杂度为O(n)。
本段代码是按照工号对职工信息进行排序,实现过程主要是通过两个while循环。外层循环是从头结点遍历到最后一个结点,并假设头结点所存的工号元素为最小值,内层循环是比较下一个结点与当前结点所存工号元素的大小,若不存在大小突变,则继续通过p遍历单链表。由此可见,时间复杂度为O(n²)。
本段代码是按照部门号对职工信息进行排序,实现过程主要是通过两个while循环。外层循环是从头结点遍历到最后一个结点,并假设头结点所存的部门号元素为最小值,内层循环是比较下一个结点与当前结点所存部门号元素的大小,若不存在大小突变,则继续通过p遍历单链表。由此可见,时间复杂度为O(n²)。
本段代码是按照工资对职工信息进行排序,实现过程主要是通过两个while循环。外层循环是从头结点遍历到最后一个结点,并假设头结点所存的工资元素为最小值,内层循环是比较下一个结点与当前结点所存工资元素的大小,若不存在大小突变,则继续通过p遍历单链表。由此可见,时间复杂度为O(n²)。
本段代码是删除指定的职工信息,主要通过从头结点遍历单链表实现。当for循环中遇到与指定工号相同的工号元素时,通过free()进行删除该元素组。由此可见,时间复杂度为O(n)。
本段代码是删除指定的职工信息,主要通过从头结点遍历单链表实现。通过while循环摸到该单链表的尾部,在遇到每一个元素组的时候,通过free()进行删除该元素组,最后将头指针的后继结点重置为NULL。由此可见,时间复杂度为O(n)。
第三题:
算法思想:q从头结点指向的下一个结点开始遍历直到链表结束,每一次寻找到最小值就存入p中,遇到更小的值就进行替换。遍历完成后,最小值p且r为p的前驱结点,然后删除p即可获得最终效果。由此可见,时间复杂度为O(n)。
其他参考代码:
#include
#include
using namespace std;
#define Elemtype char //最后没有分号
//typedef LNode *LinkList; //LinkList和LNode* 是不同的名字,但是他们是同一个指针类型,命名的不同是为了概念上更加明确。
//这里的LinkList类型的指针变量L表示它是单链表的头指针,LNode* 类型的指针变量表示它是指向某一结点的指针
class LNode{
private:
Elemtype data;
LNode *next;
public:
LNode()
{
this->next=NULL;
}
/*
void InitList_L(LNode* &L) //链表初始化函数
{
L=new LNode;
L->next=NULL;
}
void DestroyList_L(LNode* &L) //对于结构体:销毁函数 从 头结点 开始,依次释放表中每一个节点所占用的存储空间
{
LNode *p;
p=new LNode;
p->next=NULL;
while(L) //如果L存放的东西不为空,也即L指向的地方不为空,那就接着循环。 这样可以找到最后一个结点
{
p=L; //p指向的地方和L指向的地方一样
//p仅仅指向现在的L指向的这一个地方,即头结点,每一次删头结点,之前的第一个成为了头结点,那就接着删
//确实是可以通过p把L里面的一个一个删除,只删p的话就是只删了这一个结点
L=L->next; //L是一个指针,指向L这个结点,也就是头结点。 L->next指的是第L+1个结点,也就是第一个结点
delete p;
p->next=NULL;
}
}
void ClearList_L(LNode* &L) //对于结构体:清空函数 从单链表 第一个 节点开始,依次释放表中每一个节点所占用的存储空间
{
LNode *p;
LNode *q;
p=L->next; //L是头结点,L存着的就是头结点的物理地址。所以L->next就是第一个节点的物理地址
q=new LNode; //所以用这样的方法new出来的就是这个地址的头结点
while(p)
{
q=p;
p=p->next;
delete q;
q->next=NULL;
}
L->next=NULL;
}
*/
void pushback(Elemtype t) //在链表最后面添加元素
{
LNode *p;
p=new LNode; //存放数据的LNode* 指针要new,不new会出大问题。只用作遍历可以不new
p->next=NULL;
p->data=t;
LNode *pp;
pp=this;
while(pp->next!=NULL)
{
pp=pp->next;
}
pp->next=p;
}
void show() //按顺序输出链表元素
{
LNode *p;
p=this;
while(p->next!=NULL)
{
cout<next->data<<" ";
p=p->next;
//cout<<"!"<next!=NULL)
{
i++;
p=p->next;
}
return i;
}
bool isEmpty() //判断链表是否为空表
{
LNode *p;
p=this;
if(p->next==NULL)
{
return 1;
}
else
{
return 0;
}
}
Elemtype threeShow() //输出第三元素所在的位置
{
LNode *p;
p=this;
int i=0;
for(i=0;i<3;i++)
{
p=p->next;
}
return p->data;
}
int concernA() //判断字母a是否在链表里面,如果在,就输出位置
{
LNode *p;
p=this->next;
int i=0;
while(1)
{
if(p->data=='a')
{
break;
}
else
{
i++;
}
p=p->next;
if(i==5)
{
break;
}
}
if(i==5)
{
return 0;
}
else
{
return i+1;
}
}
void insert(Elemtype m,int n) //在指定地方插入元素
{
int i=0;
LNode* p;
p=new LNode;
p->data=m;
p->next=NULL;
LNode *q;
q=this;
for(i=0;inext;
}
p->next=q->next;
q->next=p;
cout<<"已经按需插入"<=n+1)
{
for(i=0;inext;
}
LNode* q;
q=p->next;
p->next=p->next->next;
delete q;
q->next=NULL;
cout<<"删除了第"<next;
}
LNode* q;
q=p->next;
p->next=NULL;
delete q;
q->next=NULL;
cout<<"删除了第"<next==NULL;
int i=0;
while(L)
{
p=L;
L=L->next;
delete p;
p->next=NULL;
cout<>t;
a.pushback(t);
i++;
}
cout<<"链表长度为:"<
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
struct emp{
int salary; //薪水
string name,depno,id; //姓名、部门编号、职工号
};
ostream& operator << (ostream& out,const emp p) //输出流
{
out<
class List{
private:
T data;
List *link;
public:
List();
~List();
void append(const T& val); // 链尾增加一个元素
void insertElement(int pos,const T& val); // 在指定位置pos后添加一个元素val
void deleteElement(const string& val); // 删除所有值为val的元素 ,有析构函数时,这个delete也可能引起析构函数的调用。
void travalList()const; // 从头节点遍历输出链表并输出长度
bool isEmpty() const; //判断是否为空
void elementPos(const int& pos); //输出第pos+1位置 因为从0开始计算
void findElement(const T& val); //输出b元素为val的位置
void findDelete(const int& pos); //查找并删除
void deletetxt(); //删除文本内容
void nwlist(); //读取职工记录
void gtin(); //读入一个记录
void sortSalary();//以下为排序
void sortId();
void sortDepno();
void writeTxt();//写入文件
};
template
List::List(){
link=NULL;
}
template
void List::append(const T& val){
List* head=this;
while((head->link)!=NULL){
head=head->link;
}
List *a = new List();
a->data=val;
head->link=a;
}
template
void List::deleteElement(const string& val)
{
int flag=0;
List* head=this;
while((head->link)!=NULL)
{
if(head->link->data.id==val)
{
flag=1;
List* tmp=head->link;
head->link=tmp->link;
tmp->link=NULL;
delete tmp;
continue;
}
if(head->link==NULL) break;
head=head->link;
}
if(flag==0)
{
cout<<"\nElement "<
void List::travalList()const
{
int l=0;
List* head=this->link;
while(head!=NULL)
{
l++;
cout<data<link;
}
cout<<"\nlength: "<
List::~List()
{
if(this->link!=NULL)
{
delete this->link;
this->link=NULL;
}
}
template
void List::deletetxt()
{
ofstream f("emp.dat",ios::trunc);
f.close();
}
template
void List::nwlist()
{
FILE* fp;
fp=freopen("emp.dat","r",stdin);
int l;
cin>>l;
for(int i=1;i<=l;i++)
{
emp tmp;
cin>>tmp.id>>tmp.name>>tmp.depno>>tmp.salary;
this->append(tmp);
}
fclose(fp);
}
template
void List::gtin()
{
emp tmp;
cin>>tmp.id>>tmp.name>>tmp.depno>>tmp.salary;
this->append(tmp);
}
template
void List::sortSalary()
{
vector q;
List* head=this->link;
while(head!=NULL)
{
q.push_back(head->data);
head=head->link;
}
for(int i=0;iq[j+1].salary)
{
emp tmp=q[j];
q[j]=q[j+1];
q[j+1]=tmp;
}
}
}
head=this->link;
int l=0;
while(head!=NULL)
{
head->data=q[l];
l++;
head=head->link;
}
}
template
void List::sortId()
{
vector q;
List* head=this->link;
while(head!=NULL)
{
q.push_back(head->data);
head=head->link;
}
for(int i=0;iq[j+1].id)
{
emp tmp=q[j];
q[j]=q[j+1];
q[j+1]=tmp;
}
}
}
head=this->link;
int l=0;
while(head!=NULL)
{
head->data=q[l];
l++;
head=head->link;
}
}
template
void List::sortDepno()
{
vector q;
List* head=this->link;
while(head!=NULL)
{
q.push_back(head->data);
head=head->link;
}
for(int i=0;iq[j+1].depno)
{
emp tmp=q[j];
q[j]=q[j+1];
q[j+1]=tmp;
}
}
}
head=this->link;
int l=0;
while(head!=NULL)
{
head->data=q[l];
l++;
head=head->link;
}
}
template
void List::writeTxt()
{
FILE* fp;
fp=freopen("emp.dat","w",stdout);
vector q;
List* head=this->link;
while(head!=NULL)
{
q.push_back(head->data);
head=head->link;
}
cout< list;
list.nwlist();
list.travalList();
list.sortSalary();
list.travalList();
list.sortDepno();
list.travalList();
list.deleteElement("001");
list.travalList();
list.deletetxt();
list.writeTxt();
return 0;
}
//在单链表里面删除一个最小结点的算法
#include
#include
using namespace std;
#define Elemtype double //最后没有分号
//typedef LNode *LinkList; //LinkList和LNode* 是不同的名字,但是他们是同一个指针类型,命名的不同是为了概念上更加明确。
//这里的LinkList类型的指针变量L表示它是单链表的头指针,LNode* 类型的指针变量表示它是指向某一结点的指针
class LNode{
private:
Elemtype data;
LNode *next;
public:
LNode()
{
this->next=NULL;
}
void pushback(Elemtype t) //在链表最后面添加元素
{
LNode *p;
p=new LNode; //存放数据的LNode* 指针要new,不new会出大问题。只用作遍历可以不new
p->next=NULL;
p->data=t;
LNode *pp;
pp=this;
while(pp->next!=NULL)
{
pp=pp->next;
}
pp->next=p;
}
void show() //按顺序输出链表元素
{
LNode *p;
p=this;
while(p->next!=NULL)
{
cout<next->data<<" ";
p=p->next;
}
}
int getLength() //输出链表长度
{
LNode* p;
p=this;
int i=0;
while(p->next!=NULL)
{
i++;
p=p->next;
}
return i;
}
void Mydelete(int n,int flag) //删除指定位置的元素
{
LNode *p;
p=this;
int i=0;
if((*this).getLength()>=n+1)
{
for(i=0;inext;
}
LNode* q;
q=p->next;
p->next=p->next->next;
delete q;
q->next=NULL;
cout<<"删除了第"<next;
}
LNode* q;
q=p->next;
p->next=NULL;
delete q;
q->next=NULL;
cout<<"删除了第"<next;
int len=(*p).getLength()+1; //因为,它此时初始位置为this->next而不是this,所以求出来长度少一
Elemtype s[10]={0},temp=0;
int i=0,flag[100]={0},j=0;
for(i=0;idata;
p=p->next;
}
temp=s[0];
for(i=1;i>t;
a.pushback(t);
i++;
}
a.show();
a.min();
a.show();
}
/*
LNode *p;
p=this;
LNode *f;
f=new LNode;
int i=0;
if(n==1)
{
f=p->next;
p->next=p->next->next;
delete f;
f->next=NULL;
}
if(n==2&&flag==1)
{
f=p->next;
p->next=p->next->next;
delete f;
f->next=NULL;
}
for(i=0;inext;
}
f=p->next;
p->next=p->next->next;
delete f;
f->next=NULL;
*/