线性表是最常用且最简单的一种数据结构,因此线性表的学习很重要。
线性表:n(n>=0)个数据元素组成的一个有限序列,可以再其任意位置上进行插入和删除操作的线性数据结构,从数据在物理内存存储形式上线性表可分为:顺序表和链表。
顺序表用一段地址连续的存储单元依次存储数据元素的线性结构,它具有随机访问内存的能力,在C语言中,一般可以用一维数组来表示线性表。
数组有静态数组和动态数组之分,所以顺序表分为静态顺序表和动态顺序表:
1.静态顺序表,申请固定的大小
// 静态顺序表
#define MAX_SIZE
typedef int DataType;
struct SeqList
{
DataType arr[MAX_SIZE];
int size;
};
2.动态顺序表,增加一个指针,当数据满时,可以开辟一块更大的内存
// 动态顺序表
typedef struct SeqList
{
DataType* array; // 数据块指针
size_t size; // 当前有效数据个数
size_t capicity; // 容量
}SeqList;
下面是一些静态顺序表的基本操作:
// 头文件
6 #include<stdlib.h>
7 #include<stdio.h>
8 #include<string.h>
9 #include<stddef.h>
10
11 #define SeqListMax 100
12
13
14 typedef char SeqListType;
15
16 typedef struct SeqList{
17 SeqListType data[SeqListMax];
18 size_t size;
19 }SeqList;
1.顺序表初始化
5 void SeqListInit(SeqList* seqlist) //初始化静态数组
6 {
7 if(seqlist == NULL){
8 // 非法输入
9 return ;
10 }
11 seqlist->size = 0;
12 }
2.尾插、尾删
尾插:插入新元素,增加元素个数,直接赋值;尾删:删除一个元素,减少有效元素个数
14 void SeqListPushBack(SeqList* seqlist, SeqListType value) //尾插
15 {
16 if(seqlist == NULL){
17 // 非法输入
18 return ;
19 }
20 if(seqlist->size >= SeqListMax){
21 // 顺序表已满
22 return ;
23 }
24 seqlist->data[seqlist->size] = value;
25 ++ seqlist->size;
26 return ;
27 }
29 void SeqListPopBack(SeqList* seqlist) // 尾删
30 {
31 if(seqlist == NULL){
32 // 非法输入
33 return ;
34 }
35 if(seqlist->size == 0){
36 // 空顺序表
37 return ;
38 }
39 -- seqlist->size;
40 return ;
41 }
3.头插、头删
头插:增加有效元素个数,需要将顺序表的元素向后搬运;头删:将后面的元素向前搬运,减少有效元素个数
43 void SeqListPushFront(SeqList* seqlist, SeqListType value) // 头插
44 {
45 if(seqlist == NULL){
46 // 非法输入
47 return;
48 }
49 if(seqlist->size > SeqListMax){
50 // 顺序表已满
51 return;
52 }
53 seqlist->size ++;
54 size_t i = seqlist->size;
55 for(; i > 0; i-- ){
56 seqlist->data[i] = seqlist->data[i-1];
57 }
58 seqlist->data[0] = value;
59 return;
60 }
62 void SeqListPopFront(SeqList* seqlist) // 头删
63 {
64 if(seqlist == NULL){
65 // 非法输入
66 return ;
67 }
68 if(seqlist->size == 0){
69 // 空链表
70 return ;
71 }
72 size_t i = 0;
73 for(; i < seqlist->size-1; i++){
74 seqlist->data[i] = seqlist->data[i+1];
75 }
76 seqlist->size --;
77 }
4.查找、更改、删除指定位置的值
顺序表有随机访问内存的能力,给定下标,直接访问顺序表的元素
79 void SeqListGet(SeqList* seqlist, size_t pos, SeqListType* data) // 查找任意位置的值
80 {
81 if(seqlist == NULL || data == NULL){
82 // 非法输入
83 return ;
84 }
85 if(pos >= seqlist->size){
86 //不存在pos下标
87 return ;
88 }
89 *data = seqlist->data[pos];
90 return;
91 }
93 void SeqListSet(SeqList* seqlist, size_t pos, SeqListType set_value) //更改指定位置的值
94 {
95 if(seqlist == NULL){
96 // 非法输入
97 return ;
98 }
99 if(pos >= seqlist->size){
100 //不存在pos下标
101 return ;
102 }
103 seqlist->data[pos] = set_value;
104 }
148 void SeqListEraser(SeqList* seqlist, size_t pos) // 删除指定位置元素
149 {
150 if(seqlist == NULL){
151 // 非法输入
152 return;
153 }
154 if(seqlist->size == 0){
155 // 空顺序表
156 return;
157 }
158 size_t i = pos;
159 for(; i < seqlist->size; i++){
160 seqlist->data[i] = seqlist->data[i+1];
161 }
162 seqlist->size --;
163 }
5.在顺序表中查找内容,返回下标
循环比较顺序表元素与查找元素是否一致
106 int SeqListFind(SeqList* seqlist, SeqListType to_find) // 查找指定值的内容,返回下标
107 {
108 if(seqlist == NULL){
109 // 非法输入
110 return -1;
111 }
112 if(seqlist->size == 0){
113 //空顺序表
114 return -1;
115 }
116 size_t i = 0;
117 while(i < seqlist->size){
118 if(seqlist->data[i] == to_find){
119 return i;
120 }
121 i++;
122 }
123 return -1;
124 }
6.在指定位置插入值
需要先将指定位置元素及其之后的元素向后搬运,在插入新元素
126 void SeqListInsert(SeqList* seqlist,size_t pos, SeqListType value) // 在指定位置插入指定值
127 {
128 if(seqlist == NULL){
129 // 非法输入
130 return;
131 }
132 if(seqlist->size >= SeqListMax){
133 // 顺序表已满
134 return ;
135 }
136 if(pos > seqlist->size){
137 // 不存在pos下标
138 return;
139 }
140 seqlist->size ++;
141 size_t i = seqlist->size;
142 for(; i > pos; i--){
143 seqlist->data[i] = seqlist->data[i-1];
144 }
145 seqlist->data[pos] = value;
146 }
7.删除指定的值(只删除第一个,删除全部)
找到要删除的值,删除后返回;删除全部:循环查找是否有删除元素,找到就删除,直到找不到退出循环
165 void SeqListDeleteOnce(SeqList* seqlist, SeqListType to_delete) //删除顺序表中指定的值, 如果存在重复元素, 只删除第一个
166 {
167 if(seqlist == NULL){
168 // 非法输入
169 return;
170 }
171 if(seqlist->size == 0){
172 // 空顺序表
173 return;
174 }
175 size_t i = 0;
176 while(i < seqlist->size){
177 if(seqlist->data[i] == to_delete){
178 SeqListEraser(seqlist, i);
179 break;
180 }
181 i++;
182 }
183 return;
184 }
186 void SeqListDeleteAll(SeqList* seqlist, SeqListType to_delete) //删除顺序表中所有的指定的值
187 {
188 if(seqlist == NULL){
189 // 非法输入
190 return;
191 }
192 if(seqlist->size == 0){
193 // 空顺序表
194 return;
195 }
196 while(1){
197 int pos = SeqListFind(seqlist, to_delete);
198 if(pos == -1){
199 return;
200 }
201 SeqListEraser(seqlist, pos);
202 }
203 }
8.顺序表元素个数
直接返回 size 值
205 int SeqListCount(SeqList *seqlist) // 顺序表元素个数
206 {
207 if(seqlist == NULL){
208 // 非法输入
209 return -1;
210 }
211 return seqlist->size;
212 }
9.冒泡排序(升序)
冒泡排序1:每次排出一个元素,排 n 次,每次比较相邻元素大小
冒泡排序2:使用回调函数,将比较相邻元素的功能封装为一个函数,再进行冒泡排序时更灵活,更改回调函数就可以
223 void SeqListBubbleSort(SeqList* seqlist) // 冒泡排序1
224 {
225 if(seqlist == NULL){
226 // 非法输入
227 return;
228 }
229 size_t count = 0;
230 for(; count < seqlist->size; count++){
231 size_t cur = 0;
232 for(; cur < seqlist->size-1-count;cur++){
233 if(seqlist->data[cur] > seqlist->data[cur+1]){
234 Swap(&seqlist->data[cur],&seqlist->data[cur+1]);
235 }
236 }
237 }
238 }
240 void Swap(SeqListType*a, SeqListType*b) // 交换函数
241 {
242 if(a == NULL || b == NULL){
243 return;
244 }
245 SeqListType tmp = *a;
246 *a = *b;
247 *b = tmp;
248 }
250 void SeqListBubbleSort2(SeqList* seqlist, int(*cmp)(SeqListType a, SeqListType b)) //冒泡排序2(回调函数)
251 {
252 if(seqlist == NULL){
253 // 非法输入
254 return;
255 }
256 size_t count = 0;
257 for(; count < seqlist->size; count++) {
258 size_t cur = 0;
259 for(; cur < seqlist->size-1-count; cur++) {
260 if(!cmp(seqlist->data[cur], seqlist->data[cur + 1])) {
261 Swap(&seqlist->data[cur], &seqlist->data[cur + 1]);
262 }
263 }
264 }
265 }
10.删除整个顺序表
将有效元素置为 0 ,整个顺序表就被删除了
267 void SeqListDestory(SeqList* seqlist)// 删除整个顺序表
268 {
269 if(seqlist == NULL){
270 // 非法输入
271 return;
272 }
273 seqlist->size = 0;
274 }