• 数据结构之顺序表实现


    顺序表简介

    顺序表就是以数组的形式来存储和管理业务节点。具体的数据结构如下图:

    顺序表数据结构图

    由上图可知,seqlist结构体就是具体的顺序表数据结构,length变量表示存储的业务节点的个数,capacity变量表示pnode指向的堆区空间容量。该堆区是一个指针数组,每一个数组元素存储一个业务节点的地址,来指向各个业务节点,因此,管理这个指针数组的是一个二级指针pnode;

    头文件说明

    //seqlist.h
    #ifndef _SEQLIST_H_
    #define _SEQLIST_H_
    
    typedef void SeqList;
    typedef void SeqListNode;
    
    typedef struct tag_SeqList{
    	int length;
    	int capacity;
    	unsigned int **pnode;
    }TSeqList;
    
    //创建并且返回一个空的线性表
    SeqList *SeqList_Create(int capacity);
    
    //销毁一个线性表
    void SeqList_Destroy(SeqList* plist);
    
    //将一个线性表list中的所有元素清空,线性表回到创建时的状态
    void SeqList_Clear(SeqList* plist);
    
    //返回一个线性表list中的所有元素个数
    int SeqList_Length(SeqList* plist);
    
    //向一个线性表list的pos位置处插入新元素node节点
    int SeqList_Insert(SeqList* plist, SeqListNode* pnode, int pos);
    
    //获取一个线性表list的pos位置处的元素
    SeqListNode* SeqList_Get(SeqList* plist, int pos);
    
    //删除一个线性表list的pos位的node节点元素,返回值为被删除的元素,NULL表示删除失败
    SeqListNode* SeqList_Delete(SeqList* plist, int pos);
    
    //遍历顺序表
    #define SeqList_Traverse(plist,node_type,number) 
    ({ 
    	int i;
    	for(i=0; i < plist->length; i++) { 
    		printf("number: %d
    ",((typeof(node_type)*)(plist->pnode[i]))->number);
    	}  })
    #endif //seqlist.h
    
    

    seqlist.h头文件是对顺序表数据结构和功能接口的抽象。在这之中,主要注意一下几点:

    • SeqList和SeqListNode的数据类型: 是将void数据类型的封装。原因之一是增强代码的可读性,其二,将void封装,是为了兼容更多种类型的业务节点。
    • 以宏函数形式遍历顺序表:首先,我想说名的一点是,遍历的功能其实在我们设计数据结构的操作函数时是没必要设计的。我们设计的是对业务节点的管理,是“增删改查”,“查”本就可以获取想要的业务节点,但当我设计是,我们常常会提到遍历的功能,可在我设计时发现,数组指针中数组元素指向的业务节点的数据类型不确定,所以无法用printf函数直接打印想要的节点数据。想尝试的解决这个问题,于是我才设计了这个宏函数。不用定义的函数的方式去实现遍历功能,是因为无法在形参中直接获取业务节点的数据类型,只能通过宏的形式获取业务节点的数据类型。测试代码如下:
    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct a{
    	char ch;
    	int num;
    }A; 
    int main ()
    {
    	A a;
    	void *ptype = NULL;
    	ptype = (void *)&a;
    	printf("%lu
    ",sizeof(typeof(ptype)));
    	return 0;
    }
    
    

    运行的结果是:4,而不是8。得到的是ptype指针的数据类型,而不是struct a这种数据类型。如果我们用定义函数的方式而不是定义宏函数的方式去实现遍历时,那么,我们接收业务节点的形参只能是“void *”类型,但我们无法在函数内部利用typeof关键子获取到形参指向的数据的数据类型,而宏函数能做到。

    功能函数实现

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "seqlist.h"
    
    //创建并且返回一个空的线性表
    SeqList *SeqList_Create(int capacity)
    {
    	TSeqList *plist = NULL;
    
    	plist = (TSeqList*)malloc(sizeof(TSeqList));
    	memset(plist, 0, sizeof(TSeqList));
    	if(NULL == plist)
    	{
    		perror("SeqList_Create TSeqList");
    		return NULL;
    	}
    	plist->pnode = (unsigned int**)malloc(sizeof(unsigned int)*capacity);
    	memset(plist->pnode, 0, sizeof(unsigned int)*capacity);
    	if(NULL == plist->pnode)
    	{
    		perror("SeqList_Create pnode");
    		return NULL;
    	}
    	//plist->length = 0;
    	plist->capacity = capacity;
    
    	return plist;
    }
    
    //销毁一个线性表
    void SeqList_Destroy(SeqList* plist)
    {
    	TSeqList *ptlist = (TSeqList*)plist;
    	if(NULL == ptlist)
    	{
    		printf("SeqList is empty(SeqList_Destroy)!
     ");
    		return ;
    	}
    
    	if(ptlist->pnode != NULL)
    	{
    		free(ptlist->pnode);
    	}
    	free(plist);
    	return ;
    }
    
    //将一个线性表list中的所有元素清空,线性表回到创建时的状态
    void SeqList_Clear(SeqList* plist)
    {
    	TSeqList *ptlist = (TSeqList*)plist;
    	if(NULL == ptlist)
    	{
    		printf("SeqList is empty(SeqList_Clear)!
     ");
    		return ;
    	}
    	ptlist->length = 0;
    	return ;
    }
    
    //返回一个线性表list中的所有元素个数
    int SeqList_Length(SeqList* plist)
    {
    	TSeqList *ptlist = (TSeqList*)plist;
    	if(NULL == ptlist)
    	{
    		printf("SeqList is empty(SeqList_Length)!
     ");
    		return -1;
    	}
    	
    	return ptlist->length;
    }
    
    //向一个线性表list的pos位置处插入新元素node节点
    int SeqList_Insert(SeqList* plist, SeqListNode* pnode, int pos)
    {
    	TSeqList *ptlist = (TSeqList*)plist;
    	if(NULL == ptlist || NULL == pnode )
    	{
    		printf("SeqList is empty(SeqList_Insert)!
     ");
    		return -1;
    	}
    	
    	if( pos<-1 || pos >= ptlist->capacity )
    	{
    		printf("pos is unvalid(SeqList_Insert)!
    ");
    		return -2;
    	}		
    
    	int i;
    	for(i=ptlist->length; i>pos; i--)
    		ptlist->pnode[i] = ptlist->pnode[i-1];
    
    	ptlist->pnode[pos] = (unsigned int*)pnode;
    	ptlist->length ++;
    
    	return 0;
    }
    
    //获取一个线性表list的pos位置处的元素
    SeqListNode* SeqList_Get(SeqList* plist, int pos)
    {
    	TSeqList *ptlist = (TSeqList*)plist;
    	if(NULL == ptlist)
    	{
    		printf("SeqList is empty(SeqList_Get)!
     ");
    		return NULL;
    	}
    
    	if( pos<-1 || pos > ptlist->capacity )
    	{
    		printf("pos is unvalid(SeqList_Insert)!
    ");
    		return NULL;
    	}		
    	return ptlist->pnode[pos];
    }
    
    //删除一个线性表list的pos位的node节点元素,返回值为被删除的元素,NULL表示删除失败
    SeqListNode* SeqList_Delete(SeqList* plist, int pos)
    {
    	TSeqList *ptlist = (TSeqList*)plist;
    	if(NULL == ptlist)
    	{
    		printf("SeqList is empty!(SeqList_Delete)
     ");
    		return NULL;
    	}
    
    	if( pos<-1 || pos > ptlist->capacity )
    	{
    		printf("pos is unvalid!(SeqList_Delete)
    ");
    		return NULL;
    	}		
    
    	SeqListNode *pnode = NULL;
    	pnode = (SeqListNode*)ptlist->pnode[pos];
    
        int i;
    	for(i=pos; i < ptlist->length; i++)
    		ptlist->pnode[i] = ptlist->pnode[i+1];
    	ptlist->length --;
    	
        return pnode;
    }
    

    功能测试代码

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "seqlist.h"
    
    typedef struct student{
    	char name[20];
    	int age;
    }student;
    
    int main(int argc, char *argv[])
    {
     	student stu1,stu2,stu3,stu4,stu5;
    
    	stu1.age = 20;
    	stu2.age = 21;
    	stu3.age = 22;
    	stu4.age = 23;
    	stu5.age = 24;
    
       TSeqList *pslist = (TSeqList*)SeqList_Create(5);
    	
    	SeqList_Insert(pslist, (SeqListNode*)&stu1, 0);
    	SeqList_Insert(pslist, (SeqListNode*)&stu2, 1);
    	SeqList_Insert(pslist, (SeqListNode*)&stu3, 2);
    	SeqList_Insert(pslist, (SeqListNode*)&stu4, 3);
    	SeqList_Insert(pslist, (SeqListNode*)&stu5, 4);
    	printf("length: %d
    ",SeqList_Length(pslist));
    	SeqList_Traverse(pslist,student,age);
    	
    	SeqList_Delete(pslist,2);
    	printf("length: %d
    ",SeqList_Length(pslist));
    	int i;
    	student *ptmp = NULL;
    	for(i=0; i < SeqList_Length(pslist); i++)
    	{	
    		ptmp = SeqList_Get(pslist,i);	
    		printf("age: %d
    ",ptmp->age);
    	}
    	SeqList_Clear(pslist);
    	SeqList_Destroy(pslist);
    	return 0;
    }
    

    总结

    学数据结构我们要做的不仅仅是学习数据结构的算法实现,更重要的是能写出一种具有普适性的工具,站在一个更高的设计策略的角度去设计代码,这点对于学习数据结构来说很重要,没有这点做支撑,学到的数据结构就只是一个空壳子,无法灵活的应用。

  • 相关阅读:
    使用 Vite 提供的常见模板创建项目
    git 上传空目录,并忽略该空目录中产生的文件变更
    SCL
    Python中时间相关的操作
    rpm的使用
    configparser
    安全随机数
    sqlite3
    多线程threading
    python小杂记
  • 原文地址:https://www.cnblogs.com/cjaaron/p/7528740.html
Copyright © 2020-2023  润新知