线性表顺序存储结构——设计与实现

1. 数据结构的基础

首先需要明确几个名词,明确数据结构研究的是什么?

 要知道的名词:数据对象,数据元素,数据项。   

struct _MyTeacher   //一种数据类型
{
	char	name[32];
	char	tile[32];
	int		age;
	char	addr[128];
};

int main21()
{
	struct _MyTeacher t1; //数据元素
struct _MyTeacher tArray[30]; //数据对象
	memset(&t1, 0, sizeof(t1));

	strcpy(t1.name, "name"); //数据项
	strcpy(t1.addr, "addr"); //数据项
	strcpy(t1.tile, "addr"); //数据项
	t1.age = 1;
}

数据结构研究:数据对象中数据元素的关系。

这些关系包括:点对点,点对多,多对多,无联系,索引。

因为学过STL,所以喜欢将数据对象直接当成容器思考,所以接下来就使用容器和节点来描述数据对象和数据元素。


2. 线性表顺序存储结构的设计

(1)容器的设计

    线性表:说明节点间的关系是点对点的。

    顺序表:说明节点间在物理上是一个接一个存储的。

    所以使用数组作为容器, SeqListNode node[?];

    数组是确定大小的,那么应该设计数组为多大呢?

    由于我们写的数据结构是用于调用,只有在调用时才知道应该多大,

    所以这个数组应该是动态分配的, SeqListNode *node;

    接下来的问题是 SeqListNode 应该是什么类型呢?

    我们希望这个库可以用于任何类型,所以代码需要和具体类型解耦和,

    因此数组上存储的不是具体类型,而是指针。

    所以 这个数组是 unsigned int *node;

    然后使用数组作为就需要两个重要的属性,capacity和length

    所以,线性表顺序存储的容器应该是:

typedef struct _tag_SeqList{
    unsigned int *node;(32位编译器适用,考虑64位就使用int **,或unsigned long *)
    int length;
    int capacity;
}TSeqList;

   (2)对外封装

    我们不希望这个容器的具体被调用者知道,所以对外的类型应该是:

typedef void SeqList;
typedef void SeqListNode;

    接下来是对外的声明:

SeqList* SeqList_Create(int capacity);

void SeqList_Destroy(SeqList* list);

void SeqList_Clear(SeqList* list);

int SeqList_Length(SeqList* list);

int SeqList_Capacity(SeqList* list);

int SeqList_Insert(SeqList* list, SeqListNode* node, int pos);

SeqListNode* SeqList_Get(SeqList* list, int pos);

SeqListNode* SeqList_Delete(SeqList* list, int pos);

   void *的指针就是封装和解耦和的关键。

(3)函数实现

  

#include 
#include 
#include 
#include "seqlist.h"


typedef struct _tag_seqlist
{
	unsigned int *node;
	int length;
	int capacity;
}TSeqList;

SeqList* SeqList_Create(int capacity)
{
	TSeqList *tlist;
	if(capacity <= 0)
	{
		printf("(capacity <= 0) err\n");
		return NULL;
	}
	tlist = (TSeqList *)malloc(sizeof(TSeqList));
	if(tlist == NULL)
	{
		printf("(tlist == NULL) err\n");
		return NULL;
	}
	memset(tlist, 0, sizeof(TSeqList));

	tlist->node = (unsigned int *)malloc(sizeof(unsigned int)*capacity);
	if(tlist->node == NULL)
	{
		printf("tlist->node == NULL err\n");
		free(tlist);
		return NULL;
	}
	memset(tlist->node, 0, sizeof(unsigned int)*capacity);
	tlist->length = 0;
	tlist->capacity = capacity;

	return tlist;
}

void SeqList_Destroy(SeqList *list)
{
	TSeqList *tlist;

	if(NULL == list)
	{
		printf("(NULL == list) err\n");
		return;
	}
	
	tlist = (TSeqList *)list;
	if(NULL == tlist->node)
	{
		free(tlist); tlist = NULL;
		return;
	}
	free(tlist->node);
	free(tlist);
        tlist = NULL;
	return ;
}

void SeqList_Clear(SeqList *list)
{
	TSeqList *tlist;

	if(NULL == list)
	{
		printf("(NULL == list) err\n");
		return;
	}

	tlist = (TSeqList *)list;
	tlist->length = 0;
	return;
}

int SeqList_Length(SeqList *list)
{
	TSeqList *tlist;

	if(NULL == list)
	{
		printf("(NULL == list) err\n");
		return -1;
	}

	tlist = (TSeqList *)list;
	return tlist->length;
}

int SeqList_Capacity(SeqList *list)
{
	TSeqList *tlist;

	if(NULL == list)
	{
		printf("(NULL == list) err\n");
		return -1;
	}

	tlist = (TSeqList *)list;
	return tlist->capacity;
}

int SeqList_Insert(SeqList *list, SeqListNode *node, int pos)
{
	TSeqList *tlist;
	int ret, i;
	if(NULL == list || NULL == node || pos < 0)
	{
		ret = -1;
		printf("(NULL == list || NULL == node || pos < 0) err\n");
		return ret;
	}

	tlist = (TSeqList *)list;

	if(tlist->length >= tlist->capacity)
	{
		ret = -1;
		printf("(tlist->length >= tlist->capacity) err\n");
		return ret;
	}

	if(pos > tlist->length)
		pos = tlist->length;

	for(i = tlist->length; i > pos; i--)
		tlist->node[i] = tlist->node[i-1];

	tlist->node[pos] = (unsigned int)node;
	tlist->length++;

	return 0;
}

SeqListNode* SeqList_Delete(SeqList *list, int pos)
{
	TSeqList *tlist;
	SeqListNode *node;
	int i;
	if(NULL == list || pos < 0)
	{
		printf("(NULL == list || pos < 0) err\n");
		return NULL;
	}

	tlist = (TSeqList *)list;

	if(tlist->length <= 0)
	{
		printf("(tlist->length <= 0) err\n");
		return NULL;
	}

	if(pos >= tlist->length)
		pos = tlist->length -1;

	node = (SeqListNode *)tlist->node[pos];

	for(i = pos; i < tlist->length -1; i++)
		tlist->node[i] = tlist->node[i+1];

	tlist->length--;

	return node;
}
SeqListNode* SeqList_Get(SeqList *list, int pos)
{
	TSeqList *tlist;
	SeqListNode *node;
	if(NULL == list || pos < 0)
	{
		printf("(NULL == list || pos < 0) err\n");
		return NULL;
	}
	tlist = (TSeqList *)list;
	if(pos >= tlist->length)
	{
		printf("(pos >= tlist->length) err\n");
		return NULL;
	}


	node = (SeqListNode *)tlist->node[pos];

	return node;
}


  通过强制转换指针类型实现解封装和解耦合就是代码的精华了。

  指针不愧为C的最强利刃。

  接下来做个测试:

#include 
#include 
#include 
#include "seqlist.h"
typedef struct _Teacher
{
	int age;
	char name[64];
}Teacher;


typedef struct _Teacher2
{
	int age;
	char name[64];
}Teacher2;

typedef struct _Teacher3
{
	int age;
	char name[64];
	int age3;

}Teacher3;
void main()
{
	int		ret = 0, i = 0;
	SeqList* list = NULL;

	Teacher t1, t2, t3, t4,t5;
	t1.age = 31;
	t2.age = 32;
	t3.age = 33;
	t4.age = 34;
	t5.age = 35;
	
	list = SeqList_Create(10);
	
	if (list == NULL)
	{
		printf("func SeqList_Create() ret :%d \n", ret);
		return ;
	}

	ret = SeqList_Insert(list, (SeqListNode*) &t1, 0); //头插法
	ret = SeqList_Insert(list, (SeqListNode*) &t2, 0); //头插法
	ret = SeqList_Insert(list, (SeqListNode*) &t3, 0); //头插法
	ret = SeqList_Insert(list, (SeqListNode*) &t4, 0); //头插法
	ret = SeqList_Insert(list, (SeqListNode*) &t5, 0); //头插法
	
	//遍历
	for (i=0; iage:%d ", tmp->age);
	}
	
	//删除链表中的节点
	while( SeqList_Length(list) > 0 )
	{
		SeqList_Delete(list, 0);
	}

	system("pause");


	return ;
}

   牛逼吧,C实现了C++模板的效果,相对于C++借助编译器多编译几份代码的原理,C更加简洁高效。

   想起老师的话,永远不要轻易说掌握了C语言。


3.总结

   线性表顺序存储的业务逻辑简单,但对于理解什么是数据结构很有帮助,同时C实现封装和业务逻辑与具体类型的解耦和很值得学习。






你可能感兴趣的:(数据结构与算法,C)