这是一篇记录《数据结构》课程课后作业的博客,我所使用的教科书是严蔚敏主编的C语言版数据结构,但是由于习惯所致,本篇博客会尽量在和书本风格同步的情况下使用C++编写程序,本文中的程序都是李岚老师上课布置的题目的个人解析,如有漏洞,欢迎指出!
绪论部分
1.写一个复数抽象类型定义,实现加乘运算
显然对于该问题,只需明确复数的组成包括实部和虚部,再了解复数加法和乘法的运算规则即可求解:
设z1 = a+bi,z2 = c+di(a、b、c、d∈R)是任意两个复数,那么
它们的和是 z1+z2 = (a+c)+(b+d)i,它们的积是z1+z2 = (ac-bd)+(bc+ad)i
编写程序如下:
#include<cstdio>
#include<iostream>
using namespace std;
typedef struct Node
{
int a; //实部;
int b; //虚部;
}Complex;
Complex Add(Complex x,Complex y)
{
Complex res;
res.a = x.a+y.a;
res.b = x.b+y.b;
return res;
}
Complex Multipy(Complex x,Complex y)
{
Complex res;
res.a = x.a*y.a-x.b*y.b;
res.b = x.b*y.a+x.a*y.b;
return res;
}
int main()
{
Complex a,b,c;
cout<<"Enter a and b, represent Complex A = a+bi"<<endl;
cin>>a.a>>a.b;
cout<<"Enter c and d, represent Complex B = c+di"<<endl;
cin>>b.a>>b.b;
c = Add(a,b);
printf("A+B = %d%+di\n",c.a,c.b);
c = Multipy(a,b);
printf("A*B = %d%+di\n",c.a,c.b);
return 0;
}
2.用流程图表示一元二次函数的求解过程
线性表部分
1.在逻辑层面求两集合的差集
显然对于该问题,由定义设集合A,B,则A与B的差集为:A-B && B-A,根据对称差运算的性质,即可编写程序如下:
#include<cstdio>
#include<iostream>
#define inf -1000000000
using namespace std;
int main()
{
int A[1000],B[1000],m,n;
cout<<"Enter m,n,indicating set A contains m elements,set B contains n elements"<<endl;
cin>>m>>n;
cout<<"Enter "<<m<<" different elems: "<<endl;
for(int i = 0; i < m; i++)
cin>>A[i];
cout<<"Enter "<<n<<" different elems: "<<endl;
for(int i = 0; i < n; i++)
cin>>B[i];
for(int i = 0; i < m; i++)
for(int j = 0; j < n; j++)
if(A[i] == B[j])
{
A[i] = B[j] = inf;
break; //A或B中不该出现重复元素,所以找到直接break;
}
cout<<"A-B: "<<endl;
for(int i = 0; i < m; i++)
if(A[i] != inf)
cout<<A[i]<<" ";
cout<<endl;
cout<<"B-A: "<<endl;
for(int i = 0; i < n; i++)
if(B[i] != inf)
cout<<B[i]<<" ";
cout<<endl;
return 0;
}
2.在顺序表A的第i个元素前插入元素B
顺序表,不用多说,先建立表A,再定位插入位置,最后插入即可
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define INIT_SIZE 100
#define DLC 10
#include<cstdlib>
#include<iostream>
using namespace std;
typedef int Status,ElemType;
typedef struct
{
ElemType *elem;
int length,listsize;
}SqList;
Status initSqlist(SqList &L)
{
L.elem = (ElemType *)malloc(INIT_SIZE*sizeof(ElemType));
if(!L.elem) exit(OVERFLOW);
L.length = 0;
L.listsize = INIT_SIZE;
return OK;
}
Status insertElem(SqList &L,int i,ElemType e)
{
if(i < 1 || i > L.length+1) return ERROR;
if(L.length >= L.listsize)
{
ElemType *newbase = (ElemType *)realloc(L.elem,(L.listsize+DLC)*sizeof(ElemType));
if(!newbase) exit(OVERFLOW);
L.elem = newbase;
L.listsize += DLC;
}
for(int j = L.length; j >= i; j--)
L.elem[j] = L.elem[j-1];
L.elem[i-1] = e;
L.length++;
return OK;
}
int main()
{
int n,m,pos;
ElemType t;
SqList L;
initSqlist(L);
cout<<"Enter n,m:"<<endl;
cin>>n>>m;
cout<<"Enter n elems to form SqList A:"<<endl;
for(int i = 1; i <= n; i++)
{
cin>>t;
insertElem(L,i,t);
}
cout<<"Enter m elems to insert(pos,elem):"<<endl;
for(int i = 0; i < m; i++)
{
cin>>pos>>t;
insertElem(L,pos,t);
}
cout<<"Result:"<<endl;
for(int i = 0; i < L.length; i++)
cout<<L.elem[i]<<" ";
cout<<endl;
return 0;
}
3. 在顺序表A的第i个元素前插入表B
这里可以把B当成一个区间,插入到A,应该先判断是否应该对A进行扩容,然后A中相应元素移位,最后代码如下:
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define INIT_SIZE 100
#define DLC 10
#include<iostream>
#include<cstdlib>
using namespace std;
typedef int Status,ElemType;
typedef struct Node
{
ElemType *elem;
int length,listsize;
}SqList;
Status initSqList(SqList &L)
{
L.elem = (ElemType *)malloc(INIT_SIZE*sizeof(ElemType));
if(!L.elem) exit(OVERFLOW);
L.length = 0;
L.listsize = INIT_SIZE;
return OK;
}
Status insertElem(SqList &L,int i,ElemType e) //单点插入;
{
if(i < 1 || i > L.length+1) return ERROR;
if(L.length >= L.listsize)
{
ElemType *tmp;
tmp = (ElemType *)realloc(L.elem,(DLC+L.listsize)*sizeof(ElemType));
if(!tmp) exit(OVERFLOW);
L.elem = tmp;
L.listsize += DLC;
}
for(int j = L.length; j >= i; j--)
L.elem[j] = L.elem[j-1];
L.elem[i-1] = e;
L.length++;
return OK;
}
Status insertList(SqList &L,int i,SqList T) //区间插入;
{
if(i < 1 || i > L.length) return ERROR;
if(L.length+T.length >= L.listsize)
{
ElemType *tmp;
tmp = (ElemType *)realloc(L.elem,(T.length+L.listsize+DLC)*sizeof(ElemType));
if(!tmp) exit(OVERFLOW);
L.elem = tmp;
L.listsize += T.length+DLC;
}
for(int j = L.length+T.length-1; j >= i-1+T.length; j--)
L.elem[j] = L.elem[j-T.length];
for(int j = i-1; j < T.length+i-1; j++)
L.elem[j] = T.elem[j-i+1];
L.length += T.length;
return OK;
}
void output(SqList L)
{
for(int i = 0; i < L.length; i++)
cout<<L.elem[i]<<" ";
cout<<endl;
}
int main()
{
int pos,m,n;
SqList L,T;
ElemType e;
initSqList(L);
initSqList(T);
cout<<"Enter m,n, indicating SqList A contains m elems, B contains n elems:"<<endl;
cin>>m>>n;
cout<<"Enter "<<m<<" elems for A:"<<endl;
for(int i = 1; i <= m; i++)
{
cin>>e;
insertElem(L,i,e);
}
cout<<"Enter "<<n<<" elems for B:"<<endl;
for(int i = 1; i <= n; i++)
{
cin>>e;
insertElem(T,i,e);
}
cout<<"Enter a position, at where you want B in A:"<<endl;
cin>>pos;
cout<<"Results:"<<endl;
if(insertList(L,pos,T))
output(L);
else cout<<"ERROR!"<<endl;
return 0;
}
4.对于顺序表A,删除从位置i起的连续k个元素
这个,也是非常简单的一个模拟,只需要找到第i个元素,将之后所有元素向前移动k位即可,注意最后顺序表长度的修改!
代码如下:
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define INIT_SIZE 100
#define DLC 10
#include<iostream>
#include<cstdlib>
using namespace std;
typedef int Status,ElemType;
typedef struct Node
{
ElemType *elem;
int length,listsize;
}SqList;
Status initSqList(SqList &L)
{
L.elem = (ElemType *)malloc(INIT_SIZE*sizeof(ElemType));
if(!L.elem) exit(OVERFLOW);
L.length = 0;
L.listsize = INIT_SIZE;
return OK;
}
Status insertElem(SqList &L,int i,ElemType e) //单点插入;
{
if(i < 1 || i > L.length+1) return ERROR;
if(L.length >= L.listsize)
{
ElemType *tmp;
tmp = (ElemType *)realloc(L.elem,(DLC+L.listsize)*sizeof(ElemType));
if(!tmp) exit(OVERFLOW);
L.elem = tmp;
L.listsize += DLC;
}
for(int j = L.length; j >= i; j++)
L.elem[j] = L.elem[j-1];
L.elem[i-1] = e;
L.length++;
return OK;
}
Status deleteRange(SqList &L,int i,int k) //区间删除;
{
if(i < 1 || i+k > L.length+1) return ERROR;
for(int j = i-1; j < L.length; j++)
L.elem[j] = L.elem[j+k];
L.length -= k;
return OK;
}
void output(SqList L)
{
for(int i = 0; i < L.length; i++)
cout<<L.elem[i]<<" ";
cout<<endl;
}
int main()
{
int pos,n,range;
SqList L;
ElemType e;
initSqList(L);
cout<<"Enter n, indicating SqList A contains n elems:"<<endl;
cin>>n;
cout<<"Enter "<<n<<" elems:"<<endl;
for(int i = 1; i <= n; i++)
{
cin>>e;
insertElem(L,i,e);
}
cout<<"Enter i,k, to delete range[i,i+k):"<<endl;
cin>>pos>>range;
cout<<"Results:"<<endl;
if(deleteRange(L,pos,range))
output(L);
else cout<<"ERROR!"<<endl;
return 0;
}
5.统计单链表中值为x的元素个数
这个题目,呃,就是把遍历函数改一下加个计数器就好了,代码如下:
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#include<iostream>
#include<cstdlib>
using namespace std;
typedef int Status,ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
Status creatLinkList(LinkList &L)
{
int n;
L = (LinkList)malloc(sizeof(LNode));
if(!L) exit(OVERFLOW);
L->data = 0;
LinkList Tail = L; //尾指针;
Tail->next = nullptr;
cout<<"Enter n:"<<endl;
cin>>n;
cout<<"Enter "<<n<<" elems to insert:"<<endl;
while(n--)
{
LinkList tmp = (LinkList)malloc(sizeof(LNode));
if(!tmp) exit(OVERFLOW);
cin>>tmp->data;
Tail->next = tmp;
Tail = tmp;
tmp = nullptr;
L->data++;
}
Tail->next = nullptr;
return OK;
}
int countX(LinkList L,ElemType x) //计数;
{
int cnt = 0;
L = L->next;
while(L)
{
if(L->data == x) cnt++;
L = L->next;
}
return cnt;
}
int main()
{
ElemType x;
LinkList L;
creatLinkList(L);
cout<<"Enter x:"<<endl;
cin>>x;
cout<<"The number of "<<x<<" in LinkList:"<<endl;
cout<<countX(L,x)<<endl;
return 0;
}
6.删除单链表中相同元素
这个题目,可以嵌套循环,第一层循环遍历链表,在第i个节点记录T->data,内层循环从i+1一直到表尾,用j作计数器,当找到和T->data相等的元素时,就删除第i+j个节点,反复如此直到循环结束即可,代码如下:
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#include<iostream>
#include<cstdlib>
using namespace std;
typedef int Status,ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
Status creatLinkList(LinkList &L)
{
int n;
L = (LinkList)malloc(sizeof(LNode));
if(!L) exit(OVERFLOW);
L->data = 0;
LinkList Tail = L; //尾指针;
Tail->next = nullptr;
cout<<"Enter n:"<<endl;
cin>>n;
cout<<"Enter "<<n<<" elems to insert:"<<endl;
while(n--)
{
LinkList tmp = (LinkList)malloc(sizeof(LNode));
if(!tmp) exit(OVERFLOW);
cin>>tmp->data;
Tail->next = tmp;
Tail = tmp;
tmp = nullptr;
L->data++;
}
Tail->next = nullptr;
return OK;
}
Status deleteElem(LinkList L,int i,ElemType &e) //单点删除;
{
if(i < 1 || i > L->data) return ERROR;
L->data--;
while(i > 1)
{
i--;
L = L->next;
}
LinkList tmp = L->next;
e = tmp->data;
L->next = tmp->next;
free(tmp);
return OK;
}
Status deleteSameElems(LinkList L) //重复元素删除;
{
int i = 1;
ElemType e;
LinkList p = L->next;
while(p)
{
int j = 1;
ElemType tmp = p->data;
LinkList t = p->next;
while(t)
{
if(t->data == tmp)
{
deleteElem(L,i+j,e);
cout<<e<<" has been deleted!"<<endl;
}
else j++;
t = t->next;
}
p = p->next;
i++;
}
return OK;
}
void Traverse(LinkList L)
{
L = L->next;
while(L)
{
cout<<L->data<<" ";
L = L->next;
}
cout<<endl;
}
int main()
{
ElemType e;
LinkList L;
creatLinkList(L);
deleteSameElems(L);
cout<<"Remaining LinkList:"<<endl;
Traverse(L);
return 0;
}
PS: 讲点题外话,今天上课学了一个有点意思的算法:单链表的转置,实际上是使用三个指针不断移动达到转置的效果,算法时间复杂度很优秀,为O(n),空间复杂度为O(1),实现如下:
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#include<iostream>
#include<cstdlib>
using namespace std;
typedef int Status,ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
Status creatLinkList(LinkList &L)
{
int n;
ElemType e;
L = (LinkList)malloc(sizeof(LNode));
if(!L) exit(OVERFLOW);
L->data = 0;
LinkList Tail = L; //尾指针;
Tail->next = nullptr;
cout<<"Enter n:"<<endl;
cin>>n;
cout<<"Enter "<<n<<" elems to insert:"<<endl;
while(n--)
{
LinkList tmp = (LinkList)malloc(sizeof(LNode));
if(!tmp) exit(OVERFLOW);
cin>>tmp->data;
Tail->next = tmp;
Tail = tmp;
tmp = nullptr;
L->data++;
}
Tail->next = nullptr;
return OK;
}
void reverseLinkList(LinkList &L)
{
if(L->data < 2) return;
LinkList p,q,r;
p = L->next;
q = p->next;
r = q->next;
p->next = nullptr; //修改表尾;
while(q->next)
{
q->next = p;
p = q;
q = r;
r = r->next;
}
q->next = p; //处理表尾;
L->next = q; //修改头指针;
}
void Traverse(LinkList L)
{
L = L->next;
while(L)
{
cout<<L->data<<" ";
L = L->next;
}
cout<<endl;
}
int main()
{
ElemType e;
LinkList L;
creatLinkList(L);
cout<<"Before reversing:"<<endl;
Traverse(L);
reverseLinkList(L);
cout<<"After reversing:"<<endl;
Traverse(L);
return 0;
}