学习链表是为了更好的学习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.声明为指针

    如果声明为结构体变量,那么在传参的时候会考进来一份临时拷贝,改掉的并不是真正的结构体数组中的值。可以用一个小程序来验证。

    #include<stdio.h>
    
    void 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提供线索。

    以上就是本人在学习过程中的一些经验总结。当然,本人能力有限,难免会有纰漏,希望大家可以指正。