《数据结构(A)》第2章作业

每位学生都应该创建一个project来存放你的(这次作业)程序。如果数据结构定义与已实现的project相同,则一定的在已有的project之下实现,并要求:

(1)单独书写新的一个.h文件;

(2)一个题目程序书写成一个新的.cpp文件;

(3)修改(也可以认为是)main文件。

如果没有定义好数据结构,则要求重新建立一个新的project,以上3个文件都需要自己写。

学生作业提交.docx文件:包括题目、思路、代码与注释、以及测试情况及其分析等(格式按模板要求)。

1  基本作业题目

2.1  (《数据结构题集(C语言版)》,第2章,第2.19题)已知线性表中的元素以值递增有序排列,并以单链表作存储结构。试写一高效的算法,删除表中所有值大于mink且小于maxk的元素(若表中存在这样的元素),同时释放被删结点空间,并分析你的算法的时间复杂度(注意:mink和maxk是给定的两个参变量,他们的值可以和表中相同,也可以不同)。

注:没有特别说明,链表均带头结点试画出与下列程序段等价的框图。

2.2  (《数据结构题集(C语言版)》,第2章,第2.21题)试写一个算法,实现顺序表的就地逆置,即利用原表存储空间,将线性表(a1, a2,……, an)逆置为(an, an-1,……, a2 , a1)。

2.3 (《数据结构题集(C语言版)》,第2章,第2.22题)试写一个算法,对单链表实现就地逆置。

注:没有特别说明,链表均带头结点。

2.4  (《数据结构题集(C语言版)》,第2章,第2.38题)设有一个双向循环链表,每个结点中除有prior, data和next三个域外,还增设了一个访问频度域freq。在链表被起用之前,频度域freq的值均初始化为零,而每当对链表进行一次locate(L,x)的操作后,被访问的结点(即元素值等于x的结点)中的频度域freq的值便增1,同时调整链表中结点之间的次序,使其按访问频度非递减的次序顺序排列,以便始终保持被频繁访问的结点总是靠近表头结点。试编写符合上述要求的locate操作的算法。

2  基本作业题目解答

【第2.1题解答】

思路:

  首先找到第一个大于mink的结点与第一个小于maxk的结点,进行标记,然后对中间的结点进行释放,再将断开的链表连在一起。

算法的时间复杂度分析:

  每次遍历检索到mink和maxk区间的结点都需要O(n)的复杂度,释放结点也是O(n)复杂度,链接新的结点是O(1)的复杂度,由于三个步骤是先后完成的,因此总的时间复杂度是O(n)。

测试情况,如图

源代码:

main.c

01:   #include "LinkList.h"
02:int main(){
03:  LinkList L;
04:  InitList (&L);
05:  int mink, maxk;
06:  printf("请输入数据数:");
07:  int n;
08:  scanf_s("%d", &n);
09:  for (int i = n; i > 0; i--) {
10:    ListInsert(L, 1, i);
11:  }
12:  printf("删除之前:");
13:  ListPrint(L);
14:  printf("请输入mink与maxk(空格隔开):");
15:  scanf_s("%d %d", &mink, &maxk);
16:  ListCdelete(L, mink, maxk);
17:  printf("删除之后:");
18:  ListPrint(L);
19:  return 0;
20:}

LinkList.h

01:#pragma once
02:#include <stdio.h>
03:#include <stdlib.h>
04:#include <malloc.h>
05:#define OK 1;
06:#define ERROR 0;
07:#define OVERFLOW 0
08:#define TRUE 1
09:#define FALSE 0
10:typedef int Status;
11:typedef int ElemType;
12:#define LIST_INT_SIZE 100
13:#define LISTINCREMENT 2
14://定义链表
15:typedef struct LNode {
16:  ElemType data;
17:  struct LNode* next;
18:}LNode,*LinkList;
19:
20://基本操作函数的声明
21:Status InitList(LinkList* L);//链表的初始化
22:Status DestroyList(LinkList* L);//链表的销毁
23:Status ListLength(LinkList L);//求链表的长度
24:Status LocateElem(LinkList L, ElemType e);//查找元素
25:Status GetElem(LinkList L, int i, ElemType* e);//获取第i个元素
26:Status ListInsert(LinkList L, int i, ElemType e);//插入元素
27:Status ListDelete(LinkList L, int i, ElemType* e);//删除元素
28:Status ListPrint(LinkList L);
29:Status ListCdelete(LinkList L, int mink, int maxk);//作业1的操作
30:Status ListTraverse(LinkList L);//遍历单链表
31:Status ListReverse(LinkList L);//单链表的逆置

2_1.c

01:#include "LinkList.h"
02:Status InitList(LinkList* L) {
03:  (*L) = (LinkList)malloc(sizeof(LNode));
04:  if (!(*L)) exit(OVERFLOW);
05:  (*L)->next = NULL;
06:  return OK;
07:}
08:Status DestroyList(LinkList* L) {
09:  free(*L);
10:  return OK;
11:}
12:Status ListLength(LinkList L) {
13:  LinkList p;
14:  p = L->next;
15:  int i = 0;
16:  while (p)
17:  {
18:    i++;
19:    p = p->next;
20:  }
21:  return i;
22:}
23:Status LocateElem(LinkList L, ElemType e) {
24:  LinkList p;
25:  p = L->next;
26:  int j = 1;
27:  while (p && p->data != e)
28:  {
29:    p = p->next;
30:    j++;
31:    if (!p) return j;
32:    else return ERROR;
33:  }
34:}
35:Status GetElem(LinkList L, int i, ElemType* e) {
36:  LinkList p = L->next;
37:  int j = 1;
38:  while (p && j < i) {
39:    p = p->next;
40:    ++j;
41:  }
42:  if (!p || j > i)
43:    return ERROR;
44:  e = p->data;
45:  return OK;
46:}
47:Status ListInsert(LinkList L, int i, ElemType e) {
48:  LinkList p = L;
49:  int j = 0;
50:  while (p && j < i - 1)//寻找第i-1个结点
51:  {
52:    p = p->next;
53:    ++j;
54:  }
55:  if (!p || j > i - 1) return ERROR;
56:  LinkList s = (LinkList)malloc(sizeof(LNode));
57:  s->data = e;
58:  s->next = p->next;
59:  p->next = s;
60:  return OK;
61:}
62:Status ListDelete(LinkList L, int i, ElemType* e) {
63:  LinkList p = L,q;
64:  int j = 0;
65:  while (p->next && j < i - 1)
66:  {
67:    p = p->next;
68:    ++j;
69:  }
70:  if (!(p->next)||j > i - 1)
71:    return ERROR;
72:  q = p->next;
73:  p->next = q->next; e = q->data;
74:  free(q);
75:  return OK;
76:}
77:Status ListPrint(LinkList L) {
78:    //遍历
79:    LinkList p = L->next;
80:    if (!p)
81:      printf("链表为空!");
82:    while (p)
83:    {
84:      printf("%d ", p->data);
85:      p = p->next;
86:    }
87:    printf("\n");
88:    return OK;
89:}
90:Status ListCdelete(LinkList L, int mink, int maxk) {
91:  LinkList p1 = L;
92:  LinkList p2 = L->next;
93:  LinkList s1, s2;
94:  if (!p2) return ERROR;
95:  // 遍历链表
96:  while (p2->data <= mink && p2) {
97:    p1 = p2;
98:    p2 = p2->next;
99:  }//记录小于mink的结点位置
100:  s1 = p1;
101:  if (!p2) return ERROR;
102:  while (p2->data < maxk && p2) {
103:    p2 = p2->next;
104:  }
105:  //记录大于maxk的结点位置
106:  //断链
107:  p1 = p1->next;
108:  while (p1 != p2) {
109:    s2 = p1->next; free(p1);
110:    p1 = s2;
111:  }
112:  //链接
113:  s1->next = p2;
114:  return OK;
115:}
116://遍历单链表,并输出数据
117:Status ListTraverse(LinkList L) {
118:  LinkList p = L -> next;
119:  if (!p) return ERROR;
120:  while (p) {
121:    printf("%d ", p->data);
122:    p = p->next;
123:  }
124:  return OK;
125:}
126:Status ListReverse(LinkList L) {
127:    LinkList p,  q;
128:    p = L->next;
129:    L->next = NULL;
130:    while (p)
131:    {
132:      //向后挪动一个位置
133:      q = p;
134:      p = p->next;
135:      //头插
136:      q->next = L->next;
137:      L->next = q;
138:    }
139:    ListTraverse(L);
140:}

【第2.2题解答】

思路:

 因为是对顺序表做逆置,因此只需要遍历n/2次,每次交换首尾两个数据即可。

结果:如图

main.c

01:#include "Sequence.h"
02:int main() {
03:  List La;
04:  InitList(&La);
05:  int i,n;
06:  printf("请输入顺序表的元素个数:");
07:  scanf_s("%d", &n);
08:  for (i = 0; i < n; i++) {
09:	ListInsert(&La, 1, i);
10:  }
11:  printf("翻转前的顺序表为:");
12:  PrintList(&La);
13:  ListReverse(&La);
14:}

Sequence.h

01:#pragma once
02:#include <stdio.h>
03:#include <stdlib.h>
04:#include <malloc.h>
05:#define OK 1;
06:#define ERROR 0;
07:#define OVERFLOW 0
08:#define TRUE 1
09:#define FALSE 0
10:#define LIST_INT_SIZE 100  //顺序表初次分配量
11:#define LISTINCREMENT 2  //线性表分配空间的增量
12:typedef int ElemType;
13:typedef int Status;
14://定义顺序表
15:typedef struct {
16:  ElemType* elem;   //存储空间首地址
17:  int length;   //已经用了的长度
18:  int listsize; //当前总存储容量
19:}List;
20://基本操作函数的声明
21:Status InitList(List *L);//顺序表的初始化
22:Status DestroyList(List* L);//顺序表的销毁
23:Status ClearList(List* L);//顺序表的清空
24:int ListLength(List L);//返回顺序表的长度
25:Status LocateElem(List L, ElemType e);//查找元素
26:Status GetElem(List L, int i, ElemType* e);//获取第i个元素
27:Status ListInsert(List* L, int i, ElemType e);//插入元素
28:Status ListDelete(List* L, int i, ElemType* e);//删除元素
29:Status ListReverse(List *L);//顺序表逆置
30:Status ListPrint(List* L);//打印顺序表

Sequence.c

01:#include "Sequence.h"
02:Status InitList(List* L) {
03:  (*L).elem = (ElemType*)malloc(sizeof(ElemType) * LIST_INT_SIZE);
04:  if (!(*L).elem) {
05:	exit(OVERFLOW);
06:  }
07:  (*L).length = 0;
08:  (*L).listsize = LIST_INT_SIZE;
09:  return OK;
10:}
11:
12:Status DestroyList(List* L) {
13:  free((*L).elem);
14:  (*L).elem = NULL;
15:  return OK;
16:}
17:
18:Status ClearList(List* L) {
19:  (*L).length = 0;
20:  return OK;
21:}
22:
23:Status ListEmpty(List* L) {
24:  //判断是否为空的表
25:  if ((*L).length == 0) {
26:	return TRUE;
27:  }
28:  else
29:	return FALSE;
30:}
31:
32:int ListLength(List L) {
33:  return L.length;
34:}
35:
36:Status GetElem(List L, int i, ElemType* e) {
37:  //先判断是否越界
38:  if (i<1 || i>L.length)
39:	return ERROR;
40:  *e = *(L.elem + i - 1);
41:  return OK;
42:}
43:
44:Status ListInsert(List* L, int i, ElemType e) {
45:  ElemType* newbase, * p, * q;
46:  //先判断是否越界
47:  if (i<1 || i>(*L).length + 1)
48:	return ERROR;
49:  //当前的空间不够 需要再分配空间
50:  if ((*L).length >= (*L).listsize) {
51:	newbase = (ElemType*)realloc((*L).elem,
52:	  ((*L).listsize + LISTINCREMENT) * sizeof(ElemType));
53:	if (!newbase) {
54:	  exit(OVERFLOW);
55:	}
56:	(*L).elem = newbase;
57:	(*L).listsize += LISTINCREMENT;
58:  }
59:
60:  //插入
61:  q = (*L).elem + i - 1;
62:  for (p = (*L).elem + (*L).length - 1; p >= q; --p) {
63:	//整体右移只能从后向前
64:	*(p + 1) = *p;
65:  }
66:  *q = e;
67:  ++(*L).length;
68:  return OK;
69:}
70:
71:Status ListDelete(List* L, int i, ElemType* e) {
72:  ElemType* p;
73:  if (i<1 || i>(*L).length)
74:	return ERROR;
75:  for (p = (*L).elem + i - 1; p < (*L).elem + (*L).length - 1; p++) {
76:	*p = *(p + 1);
77:  }
78:  (*L).length--;
79:  return OK;
80:}
81:
82:Status LocateElem(List L, ElemType e, 
83:  Status(*compare)(ElemType, ElemType)) {
84:  ElemType* p;
85:  int i = 1;
86:  p = L.elem;
87:  while (i < L.length && !(*compare)(*p++, e)) {
88:	++i;
89:  }
90:  if (i < L.length)
91:	return i;
92:  else
93:	return 0;
94:}
95:
96:Status ListReverse(List* L) {
97:  ElemType* p, * q;
98:  ElemType temp;
99:  //遍历线性表,交换前后节点,直到两个节点相遇
100:  for(p = (*L).elem, q = (*L).elem + (*L).length - 1; p < q; p++, q--)
101:  {
102:	temp = *p;
103:	*p = *q;
104:	*q = temp;
105:  }
106:  printf("翻转后的顺序表为:");
107:  PrintList(L);
108:  return OK;
109:}
110:
111:Status PrintList(List* L) {
112:  ElemType* p, * q;
113:  q = (*L).elem + (*L).length - 1;
114:  for (p = (*L).elem; p <= q; p++) {
115:	printf("%d ", *p);
116:  }
117:  printf("\n");
118:  return OK;
119:}

【第2.3题解答】

思路:

逆置链表初始为空,表中结点从原链表中依次“删除”,再逐个插入逆置链表的表头(即“头插”到逆置链表中),使它成为逆置链表的“新”的第一个结点,如此循环,直至原链表为空。

main.c

01:#include "LinkList.h"
02:int main(){
03:   LinkList L;
04:  InitList (&L);
05:  printf("请输入数据数:");
06:  int n;
07:  scanf_s("%d", &n);
08:  for (int i = n; i > 0; i--) {
09:    ListInsert(L, 1, i);
10:  }
11:  printf("逆置之前:");
12:  ListPrint(L);
13:  printf("逆置之后:");
14:  ListReverse(L);
15:}

基本函数操作实现与2_1类似,此处展示核心逆置算法

01:Status ListReverse(LinkList L) {
02:    LinkList p,  q;
03:    p = L->next;
04:    L->next = NULL;
05:    while (p)
06:    {
07:      //向后挪动一个位置
08:      q = p;
09:      p = p->next;
10:      //头插
11:      q->next = L->next;
12:      L->next = q;
13:    }
14:    ListTraverse(L);
15:}

实验结果如图

【第2.4题解答】

思路:

遍历链表,对data值等于x的节点的频度加一。

用选择排序的思路找到,链表中最大的频度的节点,标记节点位置。

交换节点,查找的值到最前面去。

实验结果如图

 源代码:

main.c

01:#include "2_4.h"
02:  int main() {
03:	DuLinkList L;
04:	InitDuList(&L);
05:	int e,n,m,i,x;
06:	printf("请输入双链表的数据个数:");
07:	scanf_s("%d", &n);
08:	for (int i = n; i > 0; i--) {
09:	  DuListInsert(&L, 1, i);
10:	}
11:	printf("原始的双链表:");
12:	DuListTraverse(L);
13:	printf("请输入您要访问几次结点:");
14:	scanf_s("%d", &m);
15:	for (int i =1; i <= m; i++){
16:	printf("第%d标记频度的双链表: ",i);
17:	printf("请输入您要访问的数:");
18:	scanf_s("%d", &x);
19:	Locate(&L, x);
20:	DuListTraverse(L);
21:}
22:	return 0;
23:  }

 2_4.h

01://基本操作的实现
02:#pragma once
03:#include <stdio.h>
04:#include <stdlib.h>
05:#include <malloc.h>
06:#define OK 1;
07:#define ERROR 0;
08:#define OVERFLOW 0
09:#define TRUE 1
10:#define FALSE 0
11:typedef int Status;
12:typedef int ElemType;
13:#define LIST_INT_SIZE 100
14:#define LISTINCREMENT 2
15:#define MINNUMBER -1000000000
16:typedef struct DuLNode {
17:  ElemType data;
18:  struct DuLNode* prior;
19:  struct DuLNode* next;
20:  int freq;
21:}DuLNode, * DuLinkList;
22:
23:Status InitDuList(DuLinkList* L);//初始化
24:Status DuListInsert(DuLinkList * L, int i, ElemType e);//插入元素
25:Status DuListTraverse(DuLinkList L);//排序
26:Status DuListDelete(DuLinkList * L, int i, ElemType * e);//删除
27:Status Locate(DuLinkList * L, ElemType x);//查找

2_4.c

01:#include "2_4.h"
02:Status InitDuList(DuLinkList* L) {
03:  (*L) = (DuLinkList)malloc(sizeof(DuLNode));
04:  if (!(*L))exit(OVERFLOW);
05:  (*L)->next = NULL;
06:  (*L)->prior = NULL;
07:  return OK;
08:}
09:
10:Status DuListInsert(DuLinkList* L, int i, ElemType e) {
11:  if (i < 1) return ERROR;
12:  int count = 0;
13:  DuLinkList p = *L;
14:  while (count < i && p)
15:  {
16:	p = p->next;
17:	count++;
18:  }//p到了插入前的第i点
19:
20:
21:  if (!p) {
22:	//处理第一个节点的插入问题
23:	DuLinkList q = (DuLinkList)malloc(sizeof(DuLNode));
24:	if (!q) return ERROR;
25:	q->data = e;
26:	q->freq = 0;
27:	(*L)->next = q;
28:	q->prior = *L;
29:	q->next = NULL;
30:  }
31:  else {
32:	//对后续节点的插入操作
33:	DuLinkList q = (DuLinkList)malloc(sizeof(DuLNode));
34:	if (!q) return ERROR;
35:	q->data = e;
36:	q->freq = 0;
37:	q->prior = p->prior;
38:	p->prior->next = q;
39:	q->next = p;
40:	p->prior = q;
41:  }
42:  return OK;
43:}
44:Status DuListTraverse(DuLinkList L) {
45:  //遍历节点,并且输出
46:  DuLinkList p = L->next;
47:  if (!p)
48:	printf("双链表为空!");
49:  while (p)
50:  {
51:	printf("%d ", p->data);
52:	p = p->next;
53:  }
54:  printf("\n");
55:  return OK;
56:}
57:
58:Status DuListDelete(DuLinkList* L, int i, ElemType* e) {
59:  if (i < 1) return ERROR;
60:  int count = 0;
61:  DuLinkList p = *L;
62:  while (count < i && p)
63:  {
64:	p = p->next;
65:	count++;
66:  }//p到了插入前的第i点
67:
68:  //断链
69:  *e = p->data;
70:  p->prior->next = p->next;
71:  p->next->prior = p->prior;
72:  free(p);
73:  return OK;
74:}
75:
76:Status Locate(DuLinkList* L, ElemType x) {
77:  DuLinkList p = (*L)->next;
78:  if (!p)
79:	printf("双链表为空!");
80:  //查找对应x的节点,并且增加频度
81:  while (p)
82:  {
83:	if (p->data == x) {
84:	  p->freq++;
85:	  break;
86:	}
87:	p = p->next;
88:  }
89:
90:  p = (*L)->next;
91:  int max = 0;
92:  DuLinkList q = (*L)->next;
93:  DuLinkList t;
94:  //选择排序的逻辑,根据freq的值进行排序
95:  while (q->next) {
96:	p = q->next;
97:	max = q->freq;
98:	t = p;
99:	//找到频度最大的节点
100:	while (p) {
101:	  if (p->freq > max) {
102:		max = p->freq;
103:		t = p;
104:	  }
105:	  p = p->next;
106:	}
107:	//交换当前节点和频度最大节点中的内容
108:	if (max != q->freq) {
109:	  int temp;
110:	  temp = t->data;
111:	  t->data = q->data;
112:	  q->data = temp;
113:
114:	  temp = t->freq;
115:	  t->freq = q->freq;
116:	  q->freq = temp;
117:	}
118:	q = q->next;
119:  }
120:  return OK;
121:}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值