学习链表是为了更好的学习c++;顺序链表又是最简单的链表。顺序链表在实现的时候有些需要注意的事情。
实现顺序链表初始化,尾部插入,尾部删除,头部插入,头部删除,选择位置插入,查找,删除某个位置上的数,删除一个。
一.首先让我们将定义一个结构体
typedef struct SeqList { DataType array[MAX_SIZE]; size_t size; }SeqList;
可以发现我在上面使用了宏和typedef。
typedef int DataType; #define MAX_SIZE 5
好处:1.需要将数组的大小改变的时候,直接改变宏的地方。
2.可以随意改变数据类型。
二.让我们来写出来上面函数的声明
void InitList(SeqList *pSeq); void PushBack(SeqList *pSeq,DataType x); void PopBack(SeqList *pSeq); void PrintfList(SeqList *pSeq); void PushFront(SeqList *pSeq, DataType x); void PopFront(SeqList *pSeq); void Insert(SeqList *pSeq, size_t pos, DataType x); int Find(SeqList *pSeq, DataType x); void Erase(SeqList *pSeq, size_t pos); void Remove(SeqList *pSeq, DataType x); void RemoveAll(SeqList *pSeq, DataType x);
1.声明为指针
如果声明为结构体变量,那么在传参的时候会考进来一份临时拷贝,改掉的并不是真正的结构体数组中的值。可以用一个小程序来验证。
#includevoid fun(int a,int b) { int z = a; a = b; b = z; printf("%d %d\n", a, b); } int main() { int a = 10; int b = 20; fun(a, b); printf("%d %d\n", a, b); system("pause"); return 0; }
为什么两个打印的结果不一样?
直接说原因,因为传参的时候考了两份临时变量给了fun函数导致在fun函数内部更改的不是内存中保存a和b的值。同样的道理,在顺序链表中,就会存在这样的问题。那么,声明为指针,传参的时候将地址传过来,在函数的内部直接操作内存就是一种很方便的方法。
二.实现函数
1.初始化
void InitList(SeqList* pSeq) { assert(pSeq); memset(pSeq->array, 0, sizeof(DataType)*MAX_SIZE); pSeq->size = 0; }
2.尾部插入
void PushBack(SeqList* pSeq, DataType x)//尾插 { assert(pSeq); if (pSeq->size >= MAX_SIZE) { printf("full\n"); return; } pSeq->array[pSeq->size] = x; pSeq->size++; //Insert(pSeq, pSeq->size, x); }
3.尾部删除
void PopBack(SeqList* pSeq)//尾删 { assert(pSeq); if (pSeq->size <= 0) { printf("empty\n"); return; } pSeq->size--; }
4.头部插入
void PushFront(SeqList *pSeq, DataType x)//头插 { assert(pSeq); int begin = pSeq->size - 1; if (pSeq->size >= MAX_SIZE) { printf("full\n"); return; } for (; begin >= 0; --begin) { pSeq->array[begin+1] = pSeq->array[begin]; } pSeq->array[0] = x; ++pSeq->size; }
5.头部删除
void PopFront(SeqList *pSeq)//头删 { assert(pSeq); int begin = 1; if (pSeq->size <= 0) { printf("empty\n"); return; } int i = pSeq->size; for (; begin < pSeq->size; ++begin) { pSeq->array[begin-1] = pSeq->array[begin]; } pSeq->size--; }
6.选择位置插入(两种写法)
void Insert(SeqList *pSeq, size_t pos, DataType x) { //[] // assert(pSeq); // assert(pos <= pSeq->size); // int begin = pSeq->size - 1; // if (pSeq->size >= MAX_SIZE) // { // printf("full\n"); // return; // } // for (; begin >= (int)pos; --begin) // { // pSeq->array[begin + 1] = pSeq->array[begin]; // } // pSeq->array[pos] = x; // ++pSeq->size; // //(] assert(pSeq); assert(pos <= pSeq->size); int begin = pSeq->size; if (pSeq->size >= MAX_SIZE) { printf("full\n"); return; } for (; begin > pos; --begin) { pSeq->array[begin] = pSeq->array[begin - 1]; } pSeq->array[pos] = x; ++pSeq->size; }
7.查找
int Find(SeqList *pSeq, DataType x) { assert(pSeq); int i = 0; for (; i < pSeq->size; ++i) { if (pSeq->array[i] == x) { return i; } } return -1; }
8.删除某个位置上的数
void Erase(SeqList *pSeq, size_t pos)//删除某个位置的数据 { assert(pSeq); assert(pos <= pSeq->size); int begin = pos+1; for (; begin <= pSeq->size; ++begin) { pSeq->array[begin - 1] = pSeq->array[begin]; } --pSeq->size; }
9.打印链表
void PrintfList(SeqList* pSeq)//打印链表 { assert(pSeq); int i = 0; for (i = 0; i < pSeq->size; i++) { printf("%d ", pSeq->array[i]); } printf("\n"); }
10.写函数需要注意的问题
1).函数的参数的有效性检查
2).边界条件
3).实现逻辑
11.×××提升的问题在实现PopBack()函数时直接调用Insert()函数时候要尤其注意这个问题。
三.单元测试
//InitList()/PushBack()/PopBack() void test1() { SeqList seq; InitList(&seq); PushBack(&seq, 1); PushBack(&seq, 2); PushBack(&seq, 3); PushBack(&seq, 4); PrintfList(&seq); PopBack(&seq); PrintfList(&seq); } //InitList()/PushFront()/PopFront() void test2() { SeqList seq; InitList(&seq); PushBack(&seq, 1); PushBack(&seq, 2); PushBack(&seq, 3); PushBack(&seq, 4); PrintfList(&seq); PushFront(&seq,0); PushFront(&seq, -1); PrintfList(&seq); PopFront(&seq); PrintfList(&seq); } void test3() { SeqList seq; InitList(&seq); PushBack(&seq, 1); PushBack(&seq, 2); PushBack(&seq, 4); PushBack(&seq, 5); Insert(&seq, 2, 3); Insert(&seq, 2, 3); PrintfList(&seq); } void test4() { SeqList seq; InitList(&seq); PushBack(&seq, 1); PushBack(&seq, 2); PushBack(&seq, 2); PushBack(&seq, 3); PushBack(&seq, 4); /*int ret = Find(&seq, 2); printf("%d\n", ret); Erase(&seq, 1); PrintfList(&seq);*/ //Remove(&seq, 2); RemoveAll(&seq, 2); PrintfList(&seq); } int main() { test4(); system("pause"); return 0; }
写大型项目的时候,单元测试是非常重要的,可以在实际开发中,避免问题的出现,并且易于定位问题,为调试修正bug提供线索。
以上就是本人在学习过程中的一些经验总结。当然,本人能力有限,难免会有纰漏,希望大家可以指正。