数据结构(线性表部分1)
数据结构习题持续更新中!!!
作业笔记!!!:
- 后续习题见数据结构(线性表习题2)
- 详细一元多项式的操作方法见文章:【数据结构】一元多项式的表示与相加(无序输入 有序输出)
- 知识点:【数据结构】线性表部分笔记1以及静态链表、循环单链表、双向链表、双向循环链表(线性表笔记2)
一、单选题
- 某线性表中最常用的操作是在最后一个元素之后插入一个元素和删除第一个元素,则采用( )存储方式最节省运算时间。
A .单链表
B .仅有头指针的单循环链表
C .双链表
D .仅有尾指针的单循环链表选D。
对于A,B,C要想在尾端插入结点,需要遍历整个链表
。
对于D,尾结点指针为p,假设插入q,q->next=p->next; p->next=q; 删除第一个元素 temp = p->next; p->next = temp->next; free(temp);
- 设一个链表最常用的操作是在末尾插入结点和删除尾结点,则选用( )最节省时间。
A . 单链表
B .单循环链表
C .带尾指针的单循环链表
D .带头结点的双循环链表选D
对于A、B需要遍历整个链表
对于C带尾指针的单向循环链表插入元素可以,但是删除尾结点不行,因为是单向的,所以在删除尾结点之前无法得到尾结点之前的那个结点。
- 对于顺序存储的线性表,访问第i个结点和增加、删除结点的时间复杂度分别为( )。
A. O(n) O(n)
B. O(n) O(1)
C. O(1) O(n)
D. O(1) O(1)
选C。顺序存储的线性表。顺序存储,简单的说就是数组,不要当成链表了。
- 线性表( a1,a2,…,an)以链接方式存储时,访问第 i 位置元素的时间复杂度为( )
A. O(i)
B. O(1)
C. O(n)
D. O(i-1)
选C。链式存储不能随机访问
- 在一个以 h 为头的单循环链中,p 指针指向链尾的条件是()
A.p->next=h
B.p->next=NULL
C.p->next->next=h
D.p->data=-1
选B。题中问的是p指针,而不是p结点
- 在双向循环链表中,在p指针所指的节点后插入一个指针q所指向的新节点,修改指针的操作是____。
q->prior=p;
q->next=p->next;
p->next->prior=q;
p->next=q;
- 双向链表中有两个指针域,llink 和 rlink,分别指回前驱及后继,设 p 指向链表中的一个结点,q指向一待插入结点,现要求在 p 前插入 q,则正确的插入为( )
p->llink->rlink =q;
q->rlink =p;
q->llink =p->llink;
p->llink:=q;
- 在双向链表指针 p 的结点前插入一个指针 q 的结点操作是( )。
q->Rlink=p;
q->Llink=p->Llink;
p->Llink->Rlink=q;
p->Llink=q;
- 在单链表指针为 p 的结点之后插入指针为 s 的结点,正确的操作是:( )。
s->next=p->next;
p->next=s;
二、算法设计题
1. 链表插入
- 设顺序表L是一个递增有序表,设计高效算法,将x插入其后仍保持L的有序性。
顺序表定义如下: typedef struct SqList{ int *elem; int length; int listsize; }SqList; 要求编写一函数 InsertX_B(SqList &L, int x),将x插入到有序表L中,保持有序性质不变
//方法一:顺序查找
void InsertX_B(SqList &L,int x){
//插入x后保证 顺序表的有序性
int *new_elem;
int i;
if(L.length==L.listsize){//空间不够用时,增大空间
new_elem=(int *)realloc(L.elem,(LIST_INST_SIZE+1)*sizeof(int));
if(new_elem==0) exit(-1); //判断是否新建成功
L.elem=new_elem;//
L.listsize= L.listsize+1;
}
for(i=0; i<L.length;i++){
//查找大于x的数的位置
if(*(L.elem+i)>x){
break;
}
}
for(int j=L.length;j>i;j--){
*(L.elem+j) = *(L.elem+j-1);//数据后移
}
*(L.elem+i)= x;//插入x
L.length++;//更新已经存放的数据长度
}//时间复杂度 O(n)
//方法二 二分查找
void InsertX_Binary(SqList &L, int x) {
int low = 0;
int high = L.length - 1;
int mid;
//插入x后保证 顺序表的有序性
int *new_elem;
if(L.length==L.listsize){//空间不够用时,增大空间
new_elem=(int *)realloc(L.elem,(LIST_INST_SIZE+1)*sizeof(int));
if(new_elem==0) exit(-1); //判断是否新建成功
L.elem=new_elem;
L.listsize= L.listsize+1;
}
while (low <= high) {
mid = (low + high) / 2;
if (L.elem[mid] > x) {
high = mid - 1;
} else {
low = mid + 1;
}
}//查找的时间复杂度为 时间复杂度:O(log2n)
// 此时 low 即为插入位置
for (int j = L.length; j > low; j--) {
L.elem[j] = L.elem[j - 1];
}
L.elem[low] = x;
L.length++;
}//时间复杂度 O(n)
2.合并链表
- 设Pa,Pb分别为两个按升序排列的单链表的头指针,用类C语言设计算法将二个单链表合并为一个按降序排列的单链表C ,要求利用原表的结点空间。 void MergeList(LinkList A, LinkList B, LinkList &C)
//将二个单链表合并为一个按 降序排列 的单链表C
方法一:新键链表C
void MergeList(LinkList A, LinkList B, LinkList &C){
//对C链表 采用首插法 实现倒序
LinkList Pa_A,Pb_B,Pc_C;
C=(LinkList)malloc(sizeof(Node));
C->next=NULL;
Pa_A=A->next;
Pb_B=B->next;
while(Pa_A!=NULL && Pb_B!=NULL){
Pc_C=(LinkList)malloc(sizeof(Node));
if(Pa_A->data < Pb_B->data) {
Pc_C->data=Pa_A->data;
Pa_A=Pa_A->next;
}
else {
Pc_C->data=Pb_B->data;
Pb_B=Pb_B->next;
}
Pc_C->next=C->next;
C->next=Pc_C;
}
while(Pa_A!=NULL){
Pc_C=(LinkList)malloc(sizeof(Node));
Pc_C->next=C->next;
C->next=Pc_C;
Pc_C->data=Pa_A->data;
Pa_A=Pa_A->next;
}
while(Pb_B!=NULL){
Pc_C=(LinkList)malloc(sizeof(Node));
Pc_C->next=C->next;
C->next=Pc_C;
Pc_C->data=Pb_B->data;
Pb_B=Pb_B->next;
}
}
//方法二
//将二个单链表合并为一个按 降序排列 的单链表C
//改变C 对A 和 B 中的数据 都用影响
void MergeList2(LinkList A, LinkList B, LinkList &C){
//
LinkList pa = A->next;
LinkList pb = B->next;
LinkList pc = A;
C=pc;
while(pa&&pb){
if(pa->data>=pb->data){
pc->next = pa;
pc = pa;
pa=pa->next;
}
else{
pc->next=pb;
pc=pb;
pb=pb->next;
}
pc->next = pa?pa:pb;
/*将 pc 指向的节点指向 pa 或 pb,
取决于哪个链表还有剩余节点。
这一步保证了即使一个链表先到达末尾,
另一个链表中剩余的节点也会全部链接到合并链表的末尾。*/
//free(B);
}
}
3. 循环单链表就地逆置
- 用类C语言设计算法实现循环单链表就地逆置
//循环链表的就低倒置
void Reverse_Circular(LinkList &Link_Circular){
if ( Link_Circular->next == Link_Circular) {
return; // 链表为空或只有一个节点,无需逆置
}
LinkList p,q;
int num=1;
p = Link_Circular->next; /*p为原链表的当前处理节点*/
while(p != Link_Circular ){ /*当原链表未处理完*/
q = p->next; /*q指针保留原链表当前处理节点的下一个节点*/
if(num){
p->next = Link_Circular; /*将当前处理节点p插入到逆置L的表头*/
num--; //对第一个结点特殊处理
}
else
p->next = Link_Circular->next;
Link_Circular->next = p;
p = q; /*p指向下一个待插入的节点*/
}
}
void Reverse1(LinkList L){
LinkList p, q;
p = L->next;
L->next = L;
while(p!=L){
q = p->next;
p->next = L->next;
L->next = p;
p = q;
}
}//Reverse
4. 删除指定区间的数据
- 设链表中的元素以递增序存储,用类C语言设计高效算法删除其中大于等于mink且小于等于maxk的元素 void ListDelete(LinkList L, int mink, int maxk)
void ListDelete(LinkList L, int mink, int maxk){
// 删除其中大于等于mink且小于等于maxk的元素
LinkList p = L->next;//p指向第一个节点
LinkList s = L; //记录p的前继结点
while(p!= NULL){
if(p->data >= mink&&p->data <= maxk){
s->next = p->next;
free(p);
p = s->next;
// 重新将p指向s,因为s->next可能也满足条件,需要再次检查
}
else{
s = p; //p的前继结点
p = p->next;//结点后移
}
}
}
//或者
void ListDelete(LinkList L, int mink, int maxk){
LinkList p,q,minp,maxp;
q = L;
p = L->next;
while( p != NULL && p->data <= mink ){
q = p;
p = p->next;
}
minp = q;
while( p != NULL && p->data < maxk ){
q = p;
p = p->next;
free(q);
}
maxp = p;
minp->next = maxp;
}//ListDelete
一元多项式的表示与相加
详细一元多项式的操作方法见文章:【数据结构】一元多项式的表示与相加(无序输入 有序输出)
14. 从键盘读入一元多项式中每一项的系数和指数,请编写算法实现(类C语言算法描述,不是完整程序代码):
(1)建立带表头结点的单链表存放一元多项式(按照指数升序排列); void CreatePoly(LinkList &pa) (2)输出一元多项式的所有数据元素(按照指数升序输出每一系数非0项的系数和指数); void Display(LinkList pa)
(3)输入自变量的值,计算一元多项式的值; int Evaluation(LinkList pa, int x),pa为头结点,x为自变量,返回值为一元多项式的值
(4)输入两个一元多项式,求一元多项式的和多项式(不是求值)。 void AddPoly(LinkList ha,LinkList hb),结果放入ha链表
//(1)建立带表头结点的单链表存放一元多项式(按照指数升序排列);
void CreatePoly(LinkList &pa)
{
int m;
cout<<"请输入 一元多项式的项数"<<endl;
cin>>m;
pa=(LinkList)malloc(sizeof(Node));
pa->next = NULL;
LinkList p,s=pa;
pa->coef_num = 0.0;;
pa->expn_num = 0;
for(int i = 0; i < m; i++){
p=(LinkList)malloc(sizeof(Node));
p->next=NULL;
if(p==NULL) return;
cout<<"请输入第"<<i+1<<"项的系数"<<endl;
cin>>p->coef_num;
p->expn_num = i;
//尾插法
s->next = p;
s=p;
}
}
//(2)输出一元多项式的所有数据元素(按照指数升序输出每一系数非0项的系数和指数);
void Display(LinkList pa) {
LinkList p=pa->next;
while(p!=NULL){
if(p->coef_num){
cout<< p->coef_num<<" "<<p->expn_num<<endl;//格式
}
p=p->next;
}
//cout<<"\b";
//cout<<endl;
}
//(3)输入自变量的值,计算一元多项式的值;
float Evaluation(LinkList pa, int x){
//pa为头结点,x为自变量,返回值为一元多项式的值
LinkList p=pa->next;
float function_sum=0.0;
while(p!=NULL){
function_sum += p->coef_num*pow(x,p->expn_num);
p=p->next;
}
return function_sum;
}
//(4)输入两个一元多项式,求一元多项式的和多项式(不是求值)。 结果放入ha链表
void AddPoly(LinkList ha,LinkList hb){
LinkList p_ha = ha->next;
LinkList p_hb = hb->next;
while(p_ha!=NULL &&p_hb!=NULL){
p_ha->coef_num += p_hb->coef_num;
p_ha = p_ha->next;
p_hb = p_hb->next;
}
p_ha = p_ha ? p_ha : p_hb;
}
感谢大家阅读!
作业笔记!!!:
- 后续习题见数据结构(线性表习题2)
- 详细一元多项式的操作方法见文章:【数据结构】一元多项式的表示与相加(无序输入 有序输出)
- 知识点:【数据结构】线性表部分笔记1以及静态链表、循环单链表、双向链表、双向循环链表(线性表笔记2)