(PTA)数据结构(作业)4、链表

判断题

1、链表的每个结点都恰好有一个指针。F

单链表有一个指针,用来指向下一个结点,双链表有两个指针,用来指向直接前驱和直接后继。

其实我觉得吧,想放几个指针不就放几个,高兴怎么用就怎么用。

2、链式存储的优点是插入、删除元素时不会引起后续元素的移动,缺点是只能顺序访问各元素。T

链式存储是依靠结点内的指针,通过指针的指向实现的逻辑上的相连,并非物理上的相连,再插入和删除的时候仅仅需要更改指针的指向,便可实现结点的插入。

3、在一个设有头指针和尾指针的单链表中,执行删除该单链表中最后一个元素的操作与链表的长度无关。F

删除最后一个元素的操作需要知道他的前驱结点,而单链表是无法通过尾指针找到最后一个元素的前驱结点的,所以依旧需要从头指针遍历到最后一个元素的前一个,所以该操作与链表的长度是有关的。

4、If N numbers are stored in a doubly linked list in increasing order, then the average time complexity for binary search is O(logN).F

如果N个数字以递增的顺序存储在一个双链表中,那么二进制搜索的平均时间复杂度为O(logN)。

binary search:对分查找;二进位检索;折半查找法;二分搜寻

链表是不能使用折半查找的,在顺序表中折半查找的时间复杂度是O(logN)

5、线性表若采用链式存储结构时,要求内存中可用存储单元的地址一定不连续。F

不一定连续

选择题

1、在具有N个结点的单链表中,实现下列哪个操作,其算法的时间复杂度是O(N)?

A、在地址为p的结点之后插入一个结点

B、删除开始结点

C、遍历链表和求链表的第i个结点

D、删除地址为p的结点的后继结点

2、在双向循环链表结点p之后插入s的语句是:

A.p->next=s; s->prior=p; p->next->prior=s ; s->next=p->next;

B.p->next->prior=s; p->next=s; s->prior=p; s->next=p->next;

C.s->prior=p; s->next=p->next; p->next=s; p->next->prior=s;

D.s->prior=p; s->next=p->next; p->next->prior=s; p->next=s;

3、If the most commonly used operations are to insert a new element after the last element, and to delete the first element in a linear list, then which of the following data structures is the most efficient?

A.singly linked list

B.singly linked circular list with a tail pointer

C.singly linked circular list with a head pointer

D.doubly linked list

4、If the most commonly used operations are to insert a new element after the last element, and to delete the last element in a linear list, then which of the following data structures is the most efficient?

A.singly linked list

B.doubly linked list

C.singly linked circular list

D.doubly linked circular list with a dummy head node

5、For two linear lists La and Lb, to link the tail of La with the head of Lb, with which one of the following data structures that we can take O(1) time and minimize the extra space?

A.singly linked list

B.singly linked circular list

C.singly linked circular list with a tail pointer

D.doubly linked circular list with a dummy head node

6、线性表若采用链式存储结构时,要求内存中可用存储单元的地址()。

A.必须是连续的

B.部分地址必须是连续的

C.一定是不连续的

D.连续或不连续都可以

7、与单链表相比,双链表的优点之一是()。

A.插入、删除操作更加简单

B.可随机访问

C.可以省略表头指针或表尾指针

D.顺序访问相邻结点更加灵活

8、可以用带表头附加结点的链表表示线性表,也可以用不带头结点的链表表示线性表,前者最主要的好处是()。

A.可以加快对表的遍历

B.使空表和非空表的处理统一

C.节省存储空间

若使用头结点,无论表是否为空,头指针都指向头结点,也就是*LNode类型,对于空表和非空表的操作是一致的。

若不使用头结点,当表非空时,头指针指向第1个结点的地址,即*LNode类型,但是对于空表,头指针指向的是NULL,此时空表和非空表的操作是不一致的。

D.可以提高存取表元素的速度

9、以下关于链式存储结构的叙述中,()是不正确的。

A.结点除自身信息外还包括指针域,因此存储密度小于顺序存储结构

B.逻辑上相邻的结点物理上不必邻接

C.可以通过计算直接确定第i个结点的存储地址

D.插入、删除运算操作方便,不必移动结点

顺序存储可以通过计算直接确定第i个元素的存储地址

10、循环链表的主要优点是()。

A.不再需要头指针了

B.已知某个结点的位置后,能够很容易找到它的直接前驱

C.在进行插入、删除运算时,能更好的保证链表不断开

D.从表中的任意结点出发都能扫描到整个链表

11、单链表的每个结点中包括一个指针next,它指向该结点的后继结点。现要将指针q指向的新结点插入到指针p指向的单链表结点之后,下面的操作序列中()是正确的。

A.q=p->next; p->next =q->next;

B.p->next =q->next; q=p->next;

C.q->next =p->next; p->next=q;

D.p->next =q; q-> next=p->next;

12、阅读下列程序,该算法的功能是()。

typedef struct node{
    ElemType data;
    struct node *next;
}LNode;
void fun2(LNode *&h){
LNode *p, *q, *r;
    if (h==NULL) return;
    p=h;
    q=h->next;
    while (q!=h )
   {
       r=q->next;
       q->next=p;
       p=q;
       q=r;
    }
    h->next=p;
    h=p;
}

A.将单链表逆置

B.将单循环链表逆置

C.从头到尾遍历单链表

D.从头到尾遍历单循环链表

13、在循环双链表的p所指结点之前插入s所指结点的操作是()。

A.p->prior = s; s->next = p; p->prior->next = s; s->prior = p->prior;

B.p->prior = s; p->prior->next = s; s->next = p; s->prior = p->prior;

C.s->next = p; s->prior = p->prior; p->prior = s; p->right->next = s;

D.s->next = p; s->prior = p->prior; p->prior->next = s; p->prior = s;

14、如果对线性表的运算只有2种,即删除第一个元素,在最后一个元素的后面插入新元素,则最好使用()。

A.只有表头指针没有表尾指针的循环单链表

B.只有表尾指针没有表头指针的循环单链表

C.非循环双链表

D.循环双链表

15、设有两个长度为n的单链表,结点类型相同。若以h1为表头指针的链表是非循环的,以h2为表头指针的链表是循环的,则()。

A.对于两个链表来说,删除第一个结点的操作,其时间复杂度都是O(1)

B.对于两个链表来说,删除最后一个结点的操作,其时间复杂度都是O(n)

C.循环链表要比非循环链表占用更多的内存空间

D.h1和h2是不同类型的变量

16、从一个具有n个结点的有序单链表中查找其值等于x的结点时,在查找成功的情况下,需要平均比较( )个结点。

A.n

B.n/2

C.(n-1)/2

D.(n+1)/2

x的位置可以是1,2,3……N中任意位置,有N种可能,即需要比较1,2,3……N次,总共比较

n(n+1)/2次,除以 N 种可能 即为答案。

17、单链表中,增加一个头结点的目的是( )。

A.使单链表至少有一个结点。

B.标识表结点中首结点的位置。

C.方便运算的实现。

D.说明单链表是线性表的链式存储。

编程题

6-1 单链表逆转 (20 分)

本题要求实现一个函数,将给定的单链表逆转。

函数接口定义:

List Reverse( List L );

其中List结构定义如下:

typedef struct Node *PtrToNode;
struct Node {
    ElementType Data; /* 存储结点数据 */
    PtrToNode   Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */

L是给定单链表,函数Reverse要返回被逆转后的链表。

裁判测试程序样例:

#include <stdio.h>
#include <stdlib.h>

typedef int ElementType;
typedef struct Node *PtrToNode;
struct Node {
    ElementType Data;
    PtrToNode   Next;
};
typedef PtrToNode List;

List Read(); /* 细节在此不表 */
void Print( List L ); /* 细节在此不表 */

List Reverse( List L );

int main()
{
    List L1, L2;
    L1 = Read();
    L2 = Reverse(L1);
    Print(L1);
    Print(L2);
    return 0;
}

/* 你的代码将被嵌在这里 */

输入样例:

5
1 3 4 5 2

输出样例:

1
2 5 4 3 1
List Reverse(List L)
{
    if (L == NULL) return;
    List p, r;
    p = NULL;
    r = NULL;
    //逐个将结点提到第一个
    //1 2 3 4 5
    //2 1 3 4 5
    //3 2 1 4 5
    //4 3 2 1 5
    //5 4 3 2 1
    while (L!=NULL)//判断是否是最后一个
    {
        r = L->Next;//如果是最后一个 此时r=NULL;
        L->Next = p;//当前结点连在上一个结点前方  两个结点逆置
        p = L;//逆置后的第一个为p
        L = r;//q = NULL
/*
第一次、r=2,1结点的next指NULL, p=1, L=2
第二次、r=3, 2结点的next指1,    p=2, L=3
第三次,r=4,3结点的next指2,    p=3,L=4
第四次、r=5,4结点的next指3,    p=4,L=5
第五次、r=NULL,5结点的next指4, p=5,L=NULL
*/
    }
    //L->Next = p;//此时L指针指的地址已经被换到了最后一个 p为第一个 首尾相连
    //将L指针重新指向变换后的链表的头结点
    return p;
}
//开头多一个List q=L,循环里L换成q,然后再加上后边的L->next=p的话,
//似乎就是循环链表的逆置了,不过while里的判断要改为q.next != L
//懒得想了,上边选择题有一道就是循环单链表的逆置

6-2 求链式表的表长 (10 分)

本题要求实现一个函数,求链式表的表长。

函数接口定义:

int Length( List L );

其中List结构定义如下:

typedef struct LNode *PtrToLNode;
struct LNode {
    ElementType Data;
    PtrToLNode Next;
};
typedef PtrToLNode List;

L是给定单链表,函数Length要返回链式表的长度。

裁判测试程序样例:

#include <stdio.h>
#include <stdlib.h>

typedef int ElementType;
typedef struct LNode *PtrToLNode;
struct LNode {
    ElementType Data;
    PtrToLNode Next;
};
typedef PtrToLNode List;

List Read(); /* 细节在此不表 */

int Length( List L );

int main()
{
    List L = Read();
    printf("%d\n", Length(L));
    return 0;
}

/* 你的代码将被嵌在这里 */

输入样例:

1 3 4 5 2 -1

输出样例:

5
int Length(List L)
{
    int n = 0;
    while (L != NULL)
    {
        n++;
        L = L->Next;
    }
    return n;
}

6-3 删除单链表偶数节点 (20 分)

本题要求实现两个函数,分别将读入的数据存储为单链表、将链表中偶数值的结点删除。链表结点定义如下:

struct ListNode {
    int data;
    struct ListNode *next;
};

函数接口定义:

struct ListNode *createlist();
struct ListNode *deleteeven( struct ListNode *head );

函数createlist从标准输入读入一系列正整数,按照读入顺序建立单链表。当读到−1时表示输入结束,函数应返回指向单链表头结点的指针。

函数deleteeven将单链表head中偶数值的结点删除,返回结果链表的头指针。

裁判测试程序样例:

#include <stdio.h>
#include <stdlib.h>

struct ListNode {
    int data;
    struct ListNode *next;
};

struct ListNode *createlist();
struct ListNode *deleteeven( struct ListNode *head );
void printlist( struct ListNode *head )
{
     struct ListNode *p = head;
     while (p) {
           printf("%d ", p->data);
           p = p->next;
     }
     printf("\n");
}

int main()
{
    struct ListNode *head;

    head = createlist();
    head = deleteeven(head);
    printlist(head);

    return 0;
}

/* 你的代码将被嵌在这里 */

输入样例:

1 2 2 3 4 5 6 7 -1

输出样例:

1 3 5 7 

struct ListNode* createlist() {
	int data;
	struct ListNode* head, * pre;
	head = pre = NULL;
	scanf("%d", &data);
	while (data != -1) {
		struct ListNode* a = (struct ListNode*)malloc(sizeof(struct ListNode));
		if (a != NULL)
		{
		a->data = data;
		a->next = NULL;
		}
		if (head == NULL) {
			head = a;
			pre = a;
		}
		else {
			pre->next = a;
			pre = a;
		}
		scanf("%d", &data);
		if (data == -1)
			break;
	}
	return head;
}
struct ListNode* deleteeven(struct ListNode* head) {
	struct ListNode* store, * i;//一个存上一个的地址,一个过度。
	int flag = 0;
	store = NULL;
	for (i = head; i != NULL;) {
		if ((i->data) % 2 == 0) {
			if (i == head) {
				store = i;
				head = head->next;
				i = head;
				free(store);
				continue;
			}
			if (i->next != NULL) {
				store->next = i->next;
				i = store->next;
				flag = 0;
				continue;
			}
			else if (i->next == NULL) {
				store->next = NULL;
				break;
			}
		}
		else {
			store = i;
			i = i->next;
		}
	}
	return head;
}

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值