在学习c语言提高-数据结构总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。
03-c提高09day_数据结构
目录:
1、单向链表
练习1:单向链表(版本二)——(+初始化、+插入、+遍历)
练习2:单向链表(版本二)——(+删除、+销毁)
2、受限线性表——栈(Stack)
(1)栈的基本概念
(2)栈的顺序存储
练习1:栈的顺序存储
(3)栈的链式存储
练习2:栈的链式存储
(4)栈的应用(案例:就近匹配)
练习:栈的应用:就近匹配
1、单向链表
(推荐版本二:代码少)
练习1:单向链表(版本二)——(+初始化、+插入、+遍历)
内存模型图如下:
单向链表(版本二).c
1 #define _CRT_SECURE_NO_WARNINGS 2 #include<stdio.h> 3 #include<string.h> 4 #include<stdlib.h> 5 6 //链表结点数据结构 7 struct LinkNode 8 { 9 struct LinkNode* next; 10 }; 11 12 //链表结构体 13 struct LList 14 { 15 struct LinkNode header;//头结点给四个字节存地址 16 int size; 17 }; 18 19 typedef void* LinkList; 20 21 //初始化链表 22 LinkList Init_LinkList() 23 { 24 struct LList* list = malloc(sizeof(struct LList)); 25 if(NULL = list) 26 { 27 return NULL; 28 } 29 list->header.next = NULL; 30 list->size = 0; 31 32 return list; 33 } 34 //插入 35 void Insert_LinkList(LinkList list, int position, void* data) 36 { 37 if(NULL = list) 38 { 39 return; 40 } 41 if(NULL = data) 42 { 43 return; 44 } 45 struct LList* mylist = (struct LList*)list; 46 struct LinkNode* mynode = (struct LinNode*)data; 47 48 if(position < 0 || position > mylist->size) 49 { 50 position = mylist->size; 51 } 52 53 //找位置(找到position位置的前一个位置) 54 struct LinkNode* pCurrent = &(mylist->header); 55 for(int i = 0; i < position; ++i) 56 { 57 pCurrent = pCurrent->next; 58 } 59 //数据入链表 60 mynode->next = pCurrent->next; 61 pCurrent->next = mynode; 62 63 mylist->size++; 64 } 65 //遍历 66 void Foreach_LinkList(LinkList list, void(*foreach)(void*)) 67 { 68 if(NULL = list) 69 { 70 return; 71 } 72 if(NULL = foreach) 73 { 74 return; 75 } 76 77 struct LList* mylist = (struct LList*)list; 78 struct LinkNode* pCurrent = &(mylist->header.next); 79 80 while(pCurrent != NULL) 81 { 82 myforeach(pCurrent); 83 pCurrent = pCurrent->next; 84 } 85 86 } 87 88 struct Person 89 { 90 struct LinkNode node;//此处不能用指针,双链表会出问题,地址的位置 91 char name[64]; 92 int age; 93 }; 94 95 void myPrint(void* data) 96 { 97 struct Person* person = (struct Person*)data; 98 printf("Name:%s Age:%d ", person->name, person->age); 99 } 100 101 void test() 102 { 103 //初始化链表 104 LinkList list = Init_LinkList(); 105 //创建数据 106 struct Person p1 = { NULL, "aaa", 10}; 107 struct Person p2 = { NULL, "bbb", 20}; 108 struct Person p3 = { NULL, "ccc", 30}; 109 struct Person p4 = { NULL, "ddd", 40}; 110 struct Person p5 = { NULL, "eee", 50}; 111 struct Person p6 = { NULL, "fff", 60}; 112 113 //插入数据 114 Insert_LinkList(list, 0, &p1); 115 Insert_LinkList(list, 0, &p2); 116 Insert_LinkList(list, 0, &p3; 117 Insert_LinkList(list, 0, &p4); 118 Insert_LinkList(list, 0, &p5); 119 Insert_LinkList(list, 0, &p6); 120 121 //遍历 122 Foreach_LinkList(list, myPrint); 123 } 124 125 int main(){ 126 127 test(); 128 129 system("pause"); 130 return EXIT_SUCCESS; 131 }
练习2:单向链表(版本二)——(+删除、+销毁)
1 #define _CRT_SECURE_NO_WARNINGS 2 #include<stdio.h> 3 #include<string.h> 4 #include<stdlib.h> 5 6 //链表结点数据结构 7 struct LinkNode 8 { 9 struct LinkNode* next; 10 }; 11 12 //链表结构体 13 struct LList 14 { 15 struct LinkNode header;//头结点给四个字节存地址 16 int size; 17 }; 18 19 typedef void* LinkList; 20 21 //初始化链表 22 LinkList Init_LinkList() 23 { 24 struct LList* list = malloc(sizeof(struct LList)); 25 if(NULL = list) 26 { 27 return NULL; 28 } 29 list->header.next = NULL; 30 list->size = 0; 31 32 return list; 33 } 34 //插入 35 void Insert_LinkList(LinkList list, int position, void* data) 36 { 37 if(NULL = list) 38 { 39 return; 40 } 41 if(NULL = data) 42 { 43 return; 44 } 45 struct LList* mylist = (struct LList*)list; 46 struct LinkNode* mynode = (struct LinNode*)data; 47 48 if(position < 0 || position > mylist->size) 49 { 50 position = mylist->size; 51 } 52 53 //找位置(找到position位置的前一个位置) 54 struct LinkNode* pCurrent = &(mylist->header); 55 for(int i = 0; i < position; ++i) 56 { 57 pCurrent = pCurrent->next; 58 } 59 //数据入链表 60 mynode->next = pCurrent->next; 61 pCurrent->next = mynode; 62 63 mylist->size++; 64 } 65 //遍历 66 void Foreach_LinkList(LinkList list, void(*foreach)(void*)) 67 { 68 if(NULL = list) 69 { 70 return; 71 } 72 if(NULL = foreach) 73 { 74 return; 75 } 76 77 struct LList* mylist = (struct LList*)list; 78 struct LinkNode* pCurrent = &(mylist->header.next); 79 80 while(pCurrent != NULL) 81 { 82 struct LinkNode* pNext = pCurrent->next; 83 myforeach(pCurrent); 84 pCurrent = pNext; 85 } 86 87 } 88 89 //删除结点 90 void RemoveByPos_LinkList(LinkList List, int position) 91 { 92 if(NULL == list) 93 { 94 return; 95 } 96 97 struct LList* mylist = (struct LList*)list; 98 99 if(position < 0 || position > mylist->size - 1) 100 { 101 return; 102 } 103 104 //辅助指针 105 struct LinkNode* pCurrent = &(mylist->header); 106 for(int i = 0; i < position; ++i) 107 { 108 pCurrent = pCurrent->next; 109 } 110 111 //缓存下待删除结点 112 struct LinkNode* pDel = pCurrent->next; 113 114 //重新建立待删除结点的前驱和后继结点关系 115 pCurrent->next = pDel->next; 116 117 mylist->size--; 118 } 119 //销毁 120 void Destroy_LinkList(LinkList list) 121 { 122 if(NULL == list) 123 { 124 return; 125 } 126 127 free(list); 128 list = NULL; 129 } 130 131 struct Person 132 { 133 struct LinkNode node;//此处不能用指针,双链表会出问题,地址的位置! 134 char name[64]; 135 int age; 136 }; 137 138 void myPrint(void* data) 139 { 140 struct Person* person = (struct Person*)data; 141 printf("Name:%s Age:%d ", person->name, person->age); 142 } 143 144 void test() 145 { 146 //初始化链表 147 LinkList list = Init_LinkList(); 148 //创建数据(缺点:不能插入重复数据,会出问题!) 149 struct Person p1 = { NULL, "aaa", 10}; 150 struct Person p2 = { NULL, "bbb", 20}; 151 struct Person p3 = { NULL, "ccc", 30}; 152 struct Person p4 = { NULL, "ddd", 40}; 153 struct Person p5 = { NULL, "eee", 50}; 154 struct Person p6 = { NULL, "fff", 60}; 155 156 //插入数据 157 Insert_LinkList(list, 0, &p1); 158 Insert_LinkList(list, 0, &p2); 159 Insert_LinkList(list, 0, &p3; 160 Insert_LinkList(list, 0, &p4); 161 Insert_LinkList(list, 0, &p5); 162 Insert_LinkList(list, 0, &p6); 163 164 //遍历 165 Foreach_LinkList(list, myPrint); 166 167 //删除 168 RemoveByPos_LinkList(list, 3); 169 printf("--------------- "); 170 171 //遍历 172 Foreach_LinkList(list, myPrint); 173 174 //销毁 175 Destroy_LinkList(list); 176 } 177 178 int main(){ 179 180 test(); 181 182 system("pause"); 183 return EXIT_SUCCESS; 184 }
2、受限线性表——栈(Stack)
(1)栈的基本概念
>概念:
首先它是一个线性表,也就是说,栈元素具有线性关系,即前驱后继关系。只不过它是一种特殊的线性表而已。定义中说是在线性表的表尾进行插入和删除操作,这里表尾是指栈顶,而不是栈底。
>特性
它的特殊之处在于限制了这个线性表的插入和删除的位置,它始终只在栈顶进行。这也就使得:栈应是固定的,最先进栈的只能在栈底。(不支持随机存取)
>操作
■栈的插入操作,叫做进栈,也称压栈。类似子弹入弹夹。
■栈的湖除操作,叫做出栈,也有的叫做猫栈,退栈。如同弹夹中的子弹出夹。
(2)栈的顺序存储
>基本概念
栈的顺序存储结构简称顺序栈,它是运算受限制的顺序表。顺序栈的存储结构是:利用一组地址连续的的存储单元依次存放自栈底到栈顶的数据元素,同时附设指针 top只是栈顶元素在顺序表中的位置。
>设计与实现
因为栈是一种特殊的线性表,所以栈的顺序存储可以通过顺序线性表来实现。
练习1:栈的顺序存储
栈的顺序存储.c
1 #define _CRT_SECURE_NO_WARNINGS 2 #include<stdio.h> 3 #include<string.h> 4 #include<stdlib.h> 5 #include"SeqStack.h"
6 struct Person 7 { 8 char name[64]; 9 int age; 10 }; 11 12 void test() 13 { 14 //初始化栈 15 SeqStack stack = Init_SeqStack(); 16 17 //创建数据 18 struct Person p1 = { "aaa", 10}; 19 struct Person p2 = { "bbb", 20}; 20 struct Person p3 = { "ccc", 30}; 21 struct Person p4 = { "ddd", 40}; 22 struct Person p5 = { "eee", 50}; 23 struct Person p6 = { "fff", 60}; 24 25 //数据入栈 26 Push_SeqStack(stack, &p1); 27 Push_SeqStack(stack, &p2); 28 Push_SeqStack(stack, &p3); 29 Push_SeqStack(stack, &p4); 30 Push_SeqStack(stack, &p5); 31 Push_SeqStack(stack, &p6); 32 33 //输出栈中所有元素 34 while(Size_SeqStack(stack) > 0) 35 { 36 //获得栈顶元素 37 struct Person* person = (struct Person*)Top_SeqStack(stack); 38 //打印 39 printf("Name:%s Age:%d ", person->name, person->age); 40 //弹出栈顶元素 41 Pop_SeqStack(stack); 42 } 43 44 printf("Size:%d ", Size_SeqStack(stack)); 45 46 //销毁栈 47 Destroy_SeqStack(stack); 48 stack = NULL; 49 } 50 51 int main(){ 52 53 test(); 54 55 system("pause"); 56 return EXIT_SUCCESS; 57 }
SeqStack.h
1 #pragma once 2 3 #include<stdlib.h> 4 #include<string.h>//memset 5 6 #ifdef __cplusplus 7 extern "C"{ 8 #endif 9 10 11 #define MAX 1024 12 13 //顺序栈数据结构 14 struct SStack 15 { 16 void* data[MAX];//存放数据的数组 17 int size;//栈中元素的个数 18 } 19 20 //数组高下标的位置当做栈顶,因为不需要移动数组中的元素在插入和删除中 21 22 //初始化 23 SeqStack Init_SeqStack(); 24 //入栈 25 void Push_SeqStack(SeqStack stack, void* data); 26 //出栈 27 void Pop_SeqStack(SeqStack stack); 28 //获得栈顶元素 29 void* Top_SeqStack(SeqStack stack); 30 //获得栈的大小 31 int Size_SeqStack(SeqStack stack); 32 //销毁栈 33 void Destroy_SeqStack(SeqStack stack); 34 35 #ifdef __cplusplus 36 } 37 #endif
SeqStack.c
1 #include"SeqStack.h" 2 3 //初始化 4 SeqStack Init_SeqStack() 5 { 6 struct SStack* stack = malloc(sizeof(struct SStack)); 7 if(NULL == stack) 8 { 9 return NULL; 10 } 11 12 memset(stack, 0, sizeof(struct SStack)); 13 stack->size = 0; 14 15 return stack; 16 } 17 //入栈 18 void Push_SeqStack(SeqStack stack, void* data) 19 { 20 if(NULL == stack) 21 { 22 return; 23 } 24 if(NULL == data) 25 { 26 return; 27 } 28 29 struct SStack* s = (struct SStack*)stack; 30 31 s->data[s->size] = data; 32 s->size++; 33 } 34 //出栈 35 void Pop_SeqStack(SeqStack stack) 36 { 37 if(NULL == stack) 38 { 39 return; 40 } 41 struct SStack* s = (struct SStack*)stack; 42 43 if(s->size == 0) 44 { 45 return; 46 } 47 48 s->data[s->size-1] = NULL;//此句可有可无,有数据会把这块内存覆盖 49 s->size--; 50 } 51 //获得栈顶元素 52 void* Top_SeqStack(SeqStack stack) 53 { 54 if(NULL == stack) 55 { 56 return NULL; 57 } 58 59 struct SStack* s = (struct SStack*)stack; 60 61 if(s->size == 0) 62 { 63 return NULL; 64 } 65 66 return s->data[s->size-1]; 67 } 68 //获得栈的大小 69 int Size_SeqStack(SeqStack stack) 70 { 71 if(NULL == stack) 72 { 73 return -1; 74 } 75 76 struct SStack* s = (struct SStack*)stack; 77 return s->size; 78 } 79 //销毁栈 80 void Destroy_SeqStack(SeqStack stack) 81 { 82 if(NULL == stack) 83 { 84 return; 85 } 86 free(stack); 87 88 }
(3)栈的链式存储
>基本概念
栈的链式存储结构简称链栈,
练习2:栈的链式存储
栈的链式存储.c
1 #define _CRT_SECURE_NO_WARNINGS 2 #include<stdio.h> 3 #include<string.h> 4 #include<stdlib.h> 5 #include"LinkStack.h"
6 struct Person 7 { 8 struct StackNode node; 9 char name[64]; 10 int age; 11 }; 12 13 void test() 14 { 15 //初始化栈 16 LinkStack stack = Init_LinkStack(); 17 18 //创建数据 19 struct Person p1 = { NULL, "aaa", 10}; 20 struct Person p2 = { NULL, "bbb", 20}; 21 struct Person p3 = { NULL, "ccc", 30}; 22 struct Person p4 = { NULL, "ddd", 40}; 23 struct Person p5 = { NULL, "eee", 50}; 24 struct Person p6 = { NULL, "fff", 60}; 25 26 //数据入栈 27 Push_LinkStack(stack, &p1); 28 Push_LinkStack(stack, &p2); 29 Push_LinkStack(stack, &p3); 30 Push_LinkStack(stack, &p4); 31 Push_LinkStack(stack, &p5); 32 Push_LinkStack(stack, &p6); 33 34 //输出栈中所有元素 35 while(Size_LinkStack(stack) > 0) 36 { 37 //获得栈顶元素 38 struct Person* person = (struct Person*)Top_LinkStack(stack); 39 //打印 40 printf("Name:%s Age:%d ", person->name, person->age); 41 //弹出栈顶元素 42 Pop_LinkStack(stack); 43 } 44 45 printf("Size:%d ", Size_LinkStack(stack)); 46 47 //销毁栈 48 Destroy_LinkStack(stack); 49 stack = NULL; 50 } 51 52 int main(){ 53 54 test(); 55 56 system("pause"); 57 return EXIT_SUCCESS; 58 }
LinkStack.h
1 #pragma once 2 3 #include<stdlib.h> 4 5 #ifdef __cplusplus 6 extern "C"{ 7 #endif 8 9 struct StackNode 10 { 11 struct StackNode* next; 12 }; 13 14 struct LStack 15 { 16 struct StackNode header;//头结点,也可以没有 17 int size; 18 }; 19 20 typedef void* LinkStack; 21 22 //初始化 23 LinkStack Init_LinkStack(); 24 //入栈 25 void Push_LinkStack(LinkStack stack, void* data); 26 //出栈 27 void Pop_LinkStack(LinkStack stack); 28 //获得栈顶元素 29 void* Top_LinkStack(LinkStack stack); 30 //获得大小 31 int Size_LinkStack(LinkStack stack); 32 //销毁栈 33 void Destroy_LinkStack(LinkStack stack); 34 35 36 #ifdef __cplusplus 37 } 38 #endif
LinkStack.c
1 #include"LinkStack.h" 2 3 //初始化 4 LinkStack Init_LinkStack() 5 { 6 struct LStack* stack = malloc(sizeof(struct LStack)); 7 if(NULL == stack) 8 { 9 return NULL; 10 } 11 stack->header.next = NULL; 12 stack->size = 0; 13 14 return stack; 15 } 16 //入栈 17 void Push_LinkStack(LinkStack stack, void* data) 18 { 19 if(NULL == stack) 20 { 21 return; 22 } 23 if(NULL == data) 24 { 25 return; 26 } 27 28 struct LStack* ls = (struct LStack*)stack; 29 struct StackNode* node = (struct StackNode*)data; 30 31 node->next = ls->header.next;//新结点的next指向ls的头结点的下一个结点 32 ls->header.next = node;//ls头结点的下一个结点指向新结点 33 34 ++(ls->size); 35 } 36 //出栈 37 void Pop_LinkStack(LinkStack stack) 38 { 39 if(NULL == stack) 40 { 41 return; 42 } 43 44 struct LStack* ls = (struct LStack*)stack; 45 46 if(ls->size == 0) 47 { 48 return; 49 } 50 51 //缓存第一个结点 52 struct StackNode* pFirst = ls->header.next; 53 54 ls->header.next = pFirst->next; 55 56 ls->size--; 57 } 58 //获得栈顶元素 59 void* Top_LinkStack(LinkStack stack) 60 { 61 if(NULL == stack) 62 { 63 return; 64 } 65 66 struct LStack* ls = (struct LStack*)stack; 67 68 if(ls->size == 0) 69 { 70 return; 71 } 72 73 return ls->header.next; 74 } 75 //获得大小 76 int Size_LinkStack(LinkStack stack) 77 { 78 if(NULL == stack) 79 { 80 return -1; 81 } 82 83 struct LStack* ls = (struct LStack*)stack; 84 85 return ls->size; 86 } 87 //销毁栈 88 void Destroy_LinkStack(LinkStack stack) 89 { 90 if(NULL == stack) 91 { 92 return; 93 } 94 95 free(stack); 96 stack = NULL; 97 }
(4)栈的应用(案例:就近匹配)
几乎所有的编译器都具有检测括号是否匹配的能力,那么如何实现编译器中的符号成对检测?如下字符串:
5+5*(6)+9/3*1)-(1+3(
>算法思路
■从第一个字符开始扫描
■当遇见普通字符时忽略,
■当遇见左符号时压入栈中
■当遇见右符号时从栈中弹出栈顶符号,并进行匹配
■匹配成功:继续读入下一个字符
■匹配失败:立即停止,并报错
■结束;
■成功;所有字符扫描完毕,且栈为空
练习:栈的应用:就近匹配
1 #define _CRT_SECURE_NO_WARNINGS 2 #include<stdio.h> 3 #include<string.h> 4 #include<stdlib.h> 5 #include"SeqStack.h" 6 7 int IsLeft(char ch) 8 { 9 return ch == "("; 10 } 11 12 int IsRight(char ch) 13 { 14 return ch == ")"; 15 } 16 17 void printError(const char* str, char* errMsg, char *pos) 18 { 19 printError("错误信息:%s ", errMsg); 20 printf("%s ", str); 21 int dis = pos - str; 22 for(int i = 0; i < dis; ++i) 23 { 24 printf(" "); 25 } 26 printf("A "); 27 } 28 29 void test() 30 { 31 const char* str = "5+5*(6)+9/3*1)-(1+3("; 32 char* p = (char*)str; 33 34 //初始化栈 35 SeqStack stack = Init_SeqStack(); 36 37 while(*p != '