每位学生都应该创建一个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:}