From 4cdb5a75e75ee9de3851c093ce50165fff71c3e0 Mon Sep 17 00:00:00 2001 From: Didnelpsun <2675350965@qq.com> Date: Mon, 9 Aug 2021 23:14:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E9=A1=BA=E5=BA=8F=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Code/Code.vcxproj | 1 + Code/Code.vcxproj.filters | 18 ++- Code/head.h | 5 +- Code/link_list.h | 4 +- Code/main.c | 27 +---- Code/sequence_list.h | 180 +++++++++++++++++++++++------ Code/test.c | 27 +++++ Code/thread_tree.h | 3 + Data-Structrue/0-summary-ex.md | 7 ++ Data-Structrue/1-linear-list-ex.md | 35 ++++++ Data-Structrue/1-linear-list.md | 55 +++++++-- 11 files changed, 290 insertions(+), 72 deletions(-) create mode 100644 Code/test.c create mode 100644 Data-Structrue/1-linear-list-ex.md diff --git a/Code/Code.vcxproj b/Code/Code.vcxproj index a3537c3..3ad470e 100644 --- a/Code/Code.vcxproj +++ b/Code/Code.vcxproj @@ -141,6 +141,7 @@ + diff --git a/Code/Code.vcxproj.filters b/Code/Code.vcxproj.filters index 9de69db..86ef3c5 100644 --- a/Code/Code.vcxproj.filters +++ b/Code/Code.vcxproj.filters @@ -24,12 +24,15 @@ 头文件 - - 源文件 - 头文件 + + 头文件 + + + 源文件 + @@ -62,5 +65,14 @@ 头文件 + + 头文件 + + + 头文件 + + + 头文件 + \ No newline at end of file diff --git a/Code/head.h b/Code/head.h index 763ee9b..8e8d2b9 100644 --- a/Code/head.h +++ b/Code/head.h @@ -1,5 +1,8 @@ // ʼ󳤶 -#define MAXSIZE 25 +#define MAXSIZE 5 +// Ĭֵ #define DEFAULTELEM 0 +// ֵ #define INFINITY 32767 +// Ĭ typedef char element_type; diff --git a/Code/link_list.h b/Code/link_list.h index 2be4aa2..dba9a53 100644 --- a/Code/link_list.h +++ b/Code/link_list.h @@ -333,7 +333,7 @@ LinkList TailBuildLinkListWithHead(LinkList list, int length) { element_type x; if (length < 1) { printf("TailBuildLinkListWithHead:输入的单链表长度过小!"); - return 1; + return NULL; } while (i < length) { scanf("%d", &x); @@ -359,7 +359,7 @@ LinkList HeadBuildLinkListWithHead(LinkList list, int length) { element_type x; if (length < 1) { printf("HeadBuildLinkListWithHead:输入的单链表长度过小!"); - return 1; + return NULL; } while (i < length) { scanf("%d", &x); diff --git a/Code/main.c b/Code/main.c index e017379..8a3cffa 100644 --- a/Code/main.c +++ b/Code/main.c @@ -1,30 +1,9 @@ #include #include -#include "head.h" -#include "sequence_list.h" -#include "link_list.h" + int main() { - /*StaticSequenceList static_list; - InitStaticSequenceList(&static_list); - DynamicSequenceList dynamic_list; - InitDynamicSequenceList(&dynamic_list); - printf("%d\n", dynamic_list.max_size); - ReIncreaseDynamicSequenceList(&dynamic_list, 25); - printf("%d\n", dynamic_list.max_size); - InsertStaticSequenceList(&static_list, 0, 2); - InsertStaticSequenceList(&static_list, 1, 6); - InsertStaticSequenceList(&static_list, 2, 5); - PrintfStaticSequenceList(static_list); - element_type i = DEFAULTELEM; - DeleteStaticSequenceList(&static_list, 1, &i); - PrintfStaticSequenceList(static_list); - printf("%d", i); - int elem = 65; - int index = LocateStaticSequenceListElement(static_list, elem); - printf("Ԫ%d%dλ\n", elem, index + 1); - return 0;*/ - LinkList list; - InitLinkList(&list); + SequenceListTest(); + return 0; } \ No newline at end of file diff --git a/Code/sequence_list.h b/Code/sequence_list.h index 7bb3562..017b35d 100644 --- a/Code/sequence_list.h +++ b/Code/sequence_list.h @@ -8,28 +8,61 @@ // 静态顺序表 typedef struct { element_type data[MAXSIZE]; + // 长度 int length; } StaticSequenceList; // 动态顺序表 typedef struct { + // 给一个指针来分配动态数组 element_type *data; // 已分配的最大容量 int max_size; + // 长度 int length; } DynamicSequenceList; // 初始化静态顺序表 int InitStaticSequenceList(StaticSequenceList* list) { - // 初初始化静态顺序表长度为0 - list->length = 0; - return 0; + if (list == NULL) { + printf("InitStaticSequenceList:指针指向为NULL!\n"); + return 1; + } + else { + // 初初始化静态顺序表长度为0 + list->length = 0; + return 0; + } +} + +// 初始化动态顺序表 +int InitDynamicSequenceList(DynamicSequenceList* list) { + if (list == NULL) { + printf("InitDynamicSequenceList:指针指向为NULL!\n"); + return 1; + } + else { + // 初初始化动态顺序表长度为0 + list->length = 0; + list->max_size = 0; + // 申请一片连续的存储空间 + element_type* space = (element_type*)malloc(MAXSIZE * sizeof(element_type)); + if (space != NULL) { + list->data = space; + list->max_size = MAXSIZE; + return 0; + } + else { + printf("InitDynamicSequenceList:分配空间失败!\n"); + return 1; + } + } } // 打印静态顺序表 int PrintfStaticSequenceList(StaticSequenceList list) { for (int i = 0; i < list.length; i++) { - printf("第%d个元素值为%d\n", i + 1, list.data[i]); + printf("第%d个元素值为%c\n", i + 1, list.data[i]); } return 0; } @@ -37,30 +70,11 @@ int PrintfStaticSequenceList(StaticSequenceList list) { // 打印动态顺序表 int PrintfDynamicSequenceList(DynamicSequenceList list) { for (int i = 0; i < list.length; i++) { - printf("第%d个元素值为%d\n", i + 1, list.data[i]); + printf("第%d个元素值为%c\n", i + 1, list.data[i]); } return 0; } -// 初始化动态顺序表 -int InitDynamicSequenceList(DynamicSequenceList* list) { - // 初初始化动态顺序表长度为0 - list->length = 0; - list->max_size = 0; - // 申请一片连续的存储空间 - element_type* space = (element_type*)malloc(MAXSIZE * sizeof(element_type)); - if (space != NULL) { - list->data = space; - list->max_size = MAXSIZE; - return 0; - } - else { - list->max_size = 0; - printf("InitDynamicSequenceList:初始化失败!\n"); - return 1; - } -} - // 分配其他地址增长动态顺序表的数据空间长度 int OtherIncreaseDynamicSequenceList(DynamicSequenceList* list, int len) { if (len <= 0) { @@ -73,7 +87,7 @@ int OtherIncreaseDynamicSequenceList(DynamicSequenceList* list, int len) { if (space != NULL) { // 建立中间变量 list->data = space; - int* temp = list->data; + element_type* temp = list->data; for (int i = 0; i < list->length; i++) { list->data[i] = temp[i]; } @@ -111,14 +125,17 @@ int ReIncreaseDynamicSequenceList(DynamicSequenceList* list, int len) { // 插入静态顺序表 int InsertStaticSequenceList(StaticSequenceList* list, int index, element_type elem) { - if (list->length == MAXSIZE) { + // 当静态顺序表已经满了就不能插入任何元素 + if (list->length >= MAXSIZE) { printf("InsertStaticSequenceList:静态顺序表空间不足,插入失败!\n"); return 1; } + // 索引位置从0开始,所以可以插入的范围是0到list->length if (index > list->length || index < 0) { - printf("InsertStaticSequenceList:插入索引超过索引范围!\n"); + printf("InsertStaticSequenceList:插入索引%d超过索引范围!\n", index); return 1; } + // 从最后一个元素开始交换后移,list->length是空的 for (int i = list->length; i > index; i--) { list->data[i] = list->data[i - 1]; } @@ -129,13 +146,19 @@ int InsertStaticSequenceList(StaticSequenceList* list, int index, element_type e // 插入动态顺序表 int InsertDynamicSequenceList(DynamicSequenceList* list, int index, element_type elem) { - if (list->length == MAXSIZE) { - ReIncreaseDynamicSequenceList(list, 1); - } if (index > list->length || index < 0) { - printf("InsertDynamicSequenceList:插入索引超过索引范围!\n"); + printf("InsertDynamicSequenceList:插入索引%d超过索引范围!\n", index); return 1; } + // 当动态顺序表已经满了,需要新增一个位置 + // 为了避免索引无效而多增加一个空间,所以放在检查索引值的后面 + if (list->length >= MAXSIZE) { + int result = ReIncreaseDynamicSequenceList(list, 1); + if (result == 1) { + printf("InsertDynamicSequenceList:申请空间失败!\n"); + return 1; + } + } for (int i = list->length; i > index; i--) { list->data[i] = list->data[i - 1]; } @@ -144,6 +167,30 @@ int InsertDynamicSequenceList(DynamicSequenceList* list, int index, element_type return 0; } +// 循环插入静态顺序表 +int LoopInsertStaticSequenceList(StaticSequenceList* list, element_type* elem, int start, int end) { + for (int i = 0; i < end; i++) { + int result = InsertStaticSequenceList(list, i, elem[i + start]); + if (result == 1) { + printf("LoopInsertStaticSequenceList:循环插入失败!\n"); + return 1; + } + } + return 0; +} + +// 循环插入动态顺序表 +int LoopInsertDynamicSequenceList(DynamicSequenceList* list, element_type* elem, int start, int end) { + for (int i = 0; i < end; i++) { + int result = InsertDynamicSequenceList(list, i, elem[i + start]); + if (result == 1) { + printf("LoopInsertDynamicSequenceList:循环插入失败!\n"); + return 1; + } + } + return 0; +} + // 删除静态顺序表 int DeleteStaticSequenceList(StaticSequenceList* list, int index, element_type *elem) { if (index >= list->length || index < 0) { @@ -152,7 +199,7 @@ int DeleteStaticSequenceList(StaticSequenceList* list, int index, element_type * } *elem = list->data[index]; for (int i = index; i < list->length; i++) { - list->data[i] = list->data[i+1]; + list->data[i] = list->data[i + 1]; } list->length--; return 0; @@ -172,6 +219,47 @@ int DeleteDynamicSequenceList(DynamicSequenceList* list, int index, element_type return 0; } +// 删除多个静态顺序表 +int MultiDeleteStaticSequenceList(StaticSequenceList* list, int index, int len, element_type* elem) { + if (index + len >= list->length || index < 0) { + printf("MultiDeleteStaticSequenceList:删除索引超过索引范围!\n"); + return 1; + } + elem = (element_type*)malloc(len * sizeof(element_type)); + if (elem == NULL) { + printf("MultiDeleteStaticSequenceList:分配空间失败!\n"); + } + else { + for (int i = index; i < list->length - len; i++) { + elem[i - index] = list->data[i]; + list->data[i] = list->data[i + len]; + } + list->length -= len; + } + list->length -= len; + return 0; +} + +// 删除多个动态顺序表 +int MultiDeleteDynamicSequenceList(DynamicSequenceList* list, int index, int len, element_type* elem) { + if (index + len >= list->length || index < 0) { + printf("MultiDeleteDynamicSequenceList:删除索引超过索引范围!\n"); + return 1; + } + elem = (element_type*)malloc(len * sizeof(element_type)); + if (elem == NULL) { + printf("MultiDeleteDynamicSequenceList:分配空间失败!\n"); + } + else { + for (int i = index; i < list->length - len; i++) { + elem[i - index] = list->data[i]; + list->data[i] = list->data[i + len]; + } + list->length -= len; + } + return 0; +} + // 按位查找静态顺序表元素 element_type GetStaticSequenceListElement(StaticSequenceList list, int index) { if (index >= list.length || index < 0) { @@ -210,4 +298,30 @@ int LocateDynamicSequenceListElement(DynamicSequenceList list, element_type elem } printf("LocateDynamicSequenceListElement:未能定位到对应值的元素!\n"); return -1; -} \ No newline at end of file +} + +// 判空静态顺序表 +int EmptyStaticSequenceList(StaticSequenceList list) { + if (list.length == 0) { + return 1; + } + else { + return 0; + } +} + +// 判空动态顺序表 +int EmptyDynamicSequenceList(DynamicSequenceList list) { + if (list.length == 0) { + return 1; + } + else { + return 0; + } +} + +// 销毁动态顺序表 +int DestroyDynamicSequenceList(DynamicSequenceList* list) { + free(list); +} + diff --git a/Code/test.c b/Code/test.c new file mode 100644 index 0000000..5fac405 --- /dev/null +++ b/Code/test.c @@ -0,0 +1,27 @@ +// ļ + +#include "head.h" +#include "sequence_list.h" + +int SequenceListTest() { + DynamicSequenceList list; + InitDynamicSequenceList(&list); + element_type a[6] = {'1','2','3','4','5','6'}; + LoopInsertDynamicSequenceList(&list, a, 0, 6); + element_type b[3] = { 9, 'a', 'e' }; + LoopInsertDynamicSequenceList(&list, b, 1, 2); + //printf("%d", list.length); + PrintfDynamicSequenceList(list); + printf("\n"); + element_type elem; + MultiDeleteDynamicSequenceList(&list, 2, 2, &elem); + PrintfDynamicSequenceList(list); + /*DynamicSequenceList dlist; + InitDynamicSequenceList(&dlist); + OtherIncreaseDynamicSequenceList(&dlist, 15); + printf("%d", dlist.max_size);*/ + int index = LocateDynamicSequenceListElement(list, '5'); + printf("%d", index); + return 0; +} + diff --git a/Code/thread_tree.h b/Code/thread_tree.h index 18eaced..a8e4a40 100644 --- a/Code/thread_tree.h +++ b/Code/thread_tree.h @@ -24,6 +24,7 @@ int InorderThread(ThreadTreeNode* node) { pre->rtag = 1; } pre = node; + return 0; } // ҵnodeΪеһĽ @@ -51,6 +52,7 @@ int InorderTraversalThreadTree(ThreadTree tree, int(*visit)(ThreadTreeNode* node for (ThreadTreeNode* p = FristInOrderNode(tree); p != NULL; p = NextInOrderNode(p)) { visit(p); } + return 0; } // ҵnodeΪǰһĽ @@ -78,4 +80,5 @@ int ReverseInorderTraversalThreadTree(ThreadTree tree, int(*visit)(ThreadTreeNod for (ThreadTreeNode* p = LastInOrderNode(tree); p != NULL; p = PreInOrderNode(p)) { visit(p); } + return 0; } \ No newline at end of file diff --git a/Data-Structrue/0-summary-ex.md b/Data-Structrue/0-summary-ex.md index ca1d54b..e51d3c5 100644 --- a/Data-Structrue/0-summary-ex.md +++ b/Data-Structrue/0-summary-ex.md @@ -199,3 +199,10 @@ $C.O(n)$ $D.O(n^2)$ 解:$A$。令执行次数为$t$,基本运算是$t+1$,然后第$t$次$x+1=t$,所以根据判断条件$t^2>n$,所以解得$t>\sqrt{n}$,所以$O(n^\frac{1}{2})$。 +2^k +**例题** 一个算法所需时间由下述递归方程表示,试求出该算法的时间复杂度的级别(或阶)。 + +$T(n)=\left\{\begin{array}{lc} 1, & n=1 \\ 2T(n/2)+n , & n>1 \end{array}\right.$ +式中,$n$是问题的规模,为简单起见,设$n$是$2$的整数次幂。 + +解:设$n$是$2$的整数次幂,所以设$n=2^k$,当执行$k$次时,$n=1$跳出循环。当$n>1$时,$T(2^k)=2T(2^{k-1})+2^k$,又$T(2^{k-1})=2T(2^{k-2})+2^{k-1}$,所以$T(2^k)=4T(2^{k-2})+2\times2^k$,根据递推式规律所以得到$T(2^k)=2^iT(2^{k-i})+i\times2^k$,即$T(2^k)=2^kT(1)+k\times2^k=2^k+k\times2^k=(k+1)\times2^k$,即$T(n)=(\log_2n+1)\times n$,即$O(n\log_2n)$。 diff --git a/Data-Structrue/1-linear-list-ex.md b/Data-Structrue/1-linear-list-ex.md new file mode 100644 index 0000000..ac052b7 --- /dev/null +++ b/Data-Structrue/1-linear-list-ex.md @@ -0,0 +1,35 @@ +# 线性表习题 + +## 基本概念 + +**例题** 以下()是一个线性表。 + +$A.$由$n$个实数组成的集合 + +$B.$由$100$个字符组成的序列 + +$C.$所有整数组成的序列 + +$D.$邻接表 + +解:$B$。线性表定义的要求为:相同数据类型、有限序列。选项$C$的元素个数是无穷个,错误;选项$A$集合中的元素没有前后驱关系,错误;选项$D$属于存储结构,线性表是一种逻辑结构,不要将二者混为一谈。只有选项$B$符合线性表定义的要求。 + +## 顺序表 + +**例题** 设线性表有$n$个元素,严格说来,以下操作中,()在顺序表上实现要比在链表上实现的效率高。 + +Ⅰ.输出第$i$($1\leqslant i\leqslant n$)个元素值。 + +Ⅱ.交换第$3$个元素与第$4$个元素的值 + +Ⅲ.顺序输出这$n$个元素的值 + +$A.$Ⅰ + +$B.$Ⅰ、Ⅲ + +$C.$Ⅰ、Ⅱ + +$D.$Ⅱ、Ⅲ + +解:$C$。对于Ⅱ,顺序表仅需$3$次交换操作;链表则需要分别找到两个结点前驱,第$4$个结点断链后再插入到第$2$个结点后,效率较低。对于Ⅲ,需依次顺序访问每个元素,时间复杂度相同。 diff --git a/Data-Structrue/1-linear-list.md b/Data-Structrue/1-linear-list.md index 0965f1c..6162f66 100644 --- a/Data-Structrue/1-linear-list.md +++ b/Data-Structrue/1-linear-list.md @@ -4,14 +4,14 @@ ### 逻辑结构 -是具有相同数据类型的n个数据元素的有限序列。n表示表长。 +是具有相同数据类型的$n$个数据元素的有限序列。$n$表示表长。 $L=(a_1,a_2,\cdots,a_i,\cdots,a_n)$,其中$i$表示元素在线性表中的位序,从一开始。 + 存在惟一的第一个元素。 + 存在惟一的最后一个元素。 -+ 除第一个元素之外,每个元素均只有一个直接前驱。 -+ 除最后一个元素之外,每个元素均只有一个直接后继。 ++ 除第一个元素(表头元素)之外,每个元素均只有一个直接前驱。 ++ 除最后一个元素(表尾元素)之外,每个元素均只有一个直接后继。 ### 物理结构 @@ -20,7 +20,7 @@ $L=(a_1,a_2,\cdots,a_i,\cdots,a_n)$,其中$i$表示元素在线性表中的位 ## 顺序表 -把逻辑上相邻的元素存储在物理位置上也相邻的存储单元中,元素之间的关系由存储单元的邻接关系来实现。 +把逻辑上相邻的元素存储在物理位置上也相邻的存储单元中,元素之间的关系由存储单元的邻接关系来实现。$i$是元素$a_i$在线性表中的位序。 ### 顺序表特点 @@ -28,14 +28,49 @@ $L=(a_1,a_2,\cdots,a_i,\cdots,a_n)$,其中$i$表示元素在线性表中的位 2. 存储密度高,只用存储数据。 3. 拓展容量不方便。 4. 插入删除操作不方便。 +5. 表中元素的逻辑地址与物理地址顺序相同。 ### 顺序表定义 -使用C语言的结构体定义顺序表,使用`typedef`定义一个ElemType表示数据基本类型,并定义最大长度MaxSize: +使用$C$语言的结构体定义顺序表,使用`typedef`定义一个`ElemType`表示数据基本类型,并定义最大长度`MAXSIZE`: -可以使用静态分配空间,也可以使用动态分配空间: +```c +// 初始化最大长度 +#define MAXSIZE 25 +// 定义默认值 +#define DEFAULTELEM 0 +// 定义最大值 +#define INFINITY 32767 +// 定义默认数据类型 +typedef char element_type; +``` -MAXSIZE表示动态顺序表当前可以使用的最大存储空间。 +可以使用静态分配空间: + +```c +// 静态顺序表 +typedef struct { + element_type data[MAXSIZE]; + // 长度 + int length; +} StaticSequenceList; +``` + +也可以使用动态分配空间,动态分配空间还是顺序的,只不过可以替换原来空间: + +```c +// 动态顺序表 +typedef struct { + // 给一个指针来分配动态数组 + element_type *data; + // 已分配的最大容量 + int max_size; + // 长度 + int length; +} DynamicSequenceList; +``` + +其中长度是指有数据的长度,而最大容量是指已经分配给动态数组的长度,插入时要考虑这个长度,不能溢出。 ### 顺序表操作 @@ -51,10 +86,12 @@ MAXSIZE表示动态顺序表当前可以使用的最大存储空间。 #### 顺序表插入 -倒序移动元素,最后将数据插入对应索引并长度减一。 +倒序移动元素,最后将数据插入对应索引并长度加一。(这是一个较好的方式,因为如果插入的话其他元素会被挤住,倒序移动元素可以正好空出位置) 插入时间复杂度为:$T(n)=O(n)$,空间复杂度为$S(n)=O(1)$。 +平均时间复杂度:假设$p_i$($n_i=\dfrac{1}{n+1}$)是$i$位置上插入一个结点的概率,则在长度为$n$的线性表中插入一个结点时所需要移动结点的平均次数为$\sum\limits_{i=1}^{n+1}p_i(n-i+1)=\sum\limits_{i=1}^{n+1}\dfrac{1}{n+1}(n-i+1)=\dfrac{1}{n+1}\sum\limits_{i=1}^{n+1}(n-i+1)=\dfrac{1}{n+1}\times\dfrac{n(n+1)}{2}=\dfrac{n}{2}$。 + #### 顺序表删除 正序移动元素并长度减一。 @@ -65,7 +102,7 @@ MAXSIZE表示动态顺序表当前可以使用的最大存储空间。 按位查找时间复杂度为$T(n)=O(1)$。 -按值查找一般都是找到第一个元素等于指定值的元素,返回其位序,如果没有找到就返回-1。按位查找时间复杂度为$T(n)=O(n)$。 +按值查找一般都是找到第一个元素等于指定值的元素,返回其位序,如果没有找到就返回$-1$。按位查找时间复杂度为$T(n)=O(n)$。 ## 单链表