数据结构与算法&线性表工具

一、什么是线性表

1.定义:线性表是最基本、最简单、也是最常用的一种数据结构。

线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的。(一般性)增加删除不会改变线性表的性质。

2.分类

在这里插入图片描述

二、线性表工具

1.问题与分析

问题导入:
数组也是一种线性表,那么有工具性吗?什么是工具性线性表?
在这里插入图片描述那么需要怎么实现?
需求分析:
1.这个线性表应该具有一定的数据存储空间;
2.这个空间应该存在一系列有关这个空间的管理的数据;
例如:空间的最大空间(capacity),有效使用空间(count);

2.工具性基本实现

根据需求分析,我采用设计一个线性控制头:

typedef struct LINEAR {
	USER_TYPE *data;.//用户需要的数据类型
	int capacity; //最大空间
	int count;//有效使用空间
}LINEAR;

再给用户一个自己输入的数据类型:

#ifndef _STICK_USERTYPE_H_
#define _STICK_USERTYPE_H_

typedef int USER_TYPE;
//这里可以根据用户个人要求修改其类型(任何类型都行,结构体更丰富)。暂定为int型

#endif

编程习惯,使用boolean值,增强代码可读性;

typedef unsigned char boolean;
#define		TRUE		1    
#define		FALSE		0

#define		NOT_FOUND	-1

有了控制头和存储位置,接着就可以初始化了。注意有初始化,就必须有销毁。boolean返回值来知道是否成功。

//初始化线性表
boolean initLinear(LINEAR **head, int capacity) {
	if(NULL != *head ) {
		return FALSE;//如果控制头引进初始化过,返回
	}

 	*head = (LINEAR *)calloc(sizeof(LINEAR), 1); //申请一个控制头
 	(*head)->data = (USER_TYPE *)calloc(sizeof(USER_TYPE), capacity); //申请一个用户自定义存储空间
 	(*head)->capacity = capacity;
 	(*head)->count = 0;

 	return TRUE;//初始化成功
}
//销毁线性表
void destoryLinear(LINEAR **head) {
	if (NULL == head || NULL == *head) {
		return;
	}

	free((*head)->data);//释放自定义数据存储空间
	free(*head); //释放控制头空间
	*head = NULL; //指向控制头的指针销毁	
}

3.工具功能性实现

一个工具如果仅仅是使用,那么是不够的。必须的考虑到用户的使用需求。
例:用户想得到这个工具是空间大小和已经使用空间

//得到最大空间量
int getCapacity(const LINEAR *head) {
	return head->capacity;
}
//得到有效使用空间量
int getCount(const LINEAR *head) {
	return head->count;
}

例:空间是满还是空的?

boolean isLinearFull(const LINEAR *head) {
	/*if (head->count >= head->capacity) {
		return TRUE;
	}
	return FALSE;*/
	return head->count >= head->capacity;
}
//判断线性表是否为空
boolean isLinearEmpty(const LINEAR *head) {
	return head->count <= 0;
}

上面的四个例子都是一个线性表基本的属性。
接下来是功能的实现。面对一串数字,你想干啥?

1.可以修改某个值;

//修改线性表元素
boolean setElementAt (const LINEAR *head, int index, USER_TYPE data) {
	if (NULL == head || index < 0 || index >= head->capacity) {
		return FALSE;
	}
	head->data[index] = data; //修改

	return TRUE;
}

2.可以指定位置插入某个值。追加就是最后的插入;

//追加线性表元素
boolean appendElementAt(LINEAR *head, USER_TYPE data) {
	//追加是插入到最后的插入数据
	return insertElementAt(head, head->count, data);
}
//插入线性表元素
boolean insertElementAt(LINEAR *head, int index, USER_TYPE data) {
	int i;
	if (NULL == head || isLinearFull(head)
		|| index < 0 || index > head->count ) {
		return FALSE;
	}
	
	for (i = head->count; i > index; i--) {
		head->data[i] = head->data[i-1]; // 从最后一个元素开始,依次向后移动,空出插入位置空间
	}
	head->data[index] = data; //实现插入
	++head->count; //有效元素增加

	return TRUE;//插入成功+
}

3.可以通过值找位置,通过位置找值;

//得到指定位置的线性表元素
boolean getElemenAt(const LINEAR *head, int index, USER_TYPE *data) {
	if (NULL == head || index < 0 || index > head->count) {
		return FALSE;
	}
	*data = head->data[index]; //将指定指定位置的线性表元素复制下,可以用来展示

	return TRUE;
}
//查找某一元素
int elementIndexOf(const LINEAR *head, USER_TYPE data, 
	boolean (*eq)(USER_TYPE, USER_TYPE)) {
	int index;
	if (NULL == head || isLinearEmpty(head)) {
		return NOT_FOUND;
	}
	
	for (index = 0; index < head->count; index++) {
		if (eq(data, head->data[index])) {
			return index; //遍历已有的元素,找到返回其位置
		}
	}

	return NOT_FOUND; // 没找到
}

4.可以删除某个值;

//清空线性表
void clearLinear(LINEAR *head) {
	head->count = 0;
}
//删除线性表某一元素
boolean removeElementAt(LINEAR *head, int index, USER_TYPE *data) {
	if (NULL == head || isLinearEmpty(head)
		|| index < 0 || index >= head->count) {
		return FALSE;
	}

	for (; index < head->count - 1; index++) {
		head->data[index] = head->data[index + 1]; //从最后一个元素,依次向前移动一位
	}
	head->count--;//有效元素个数减1

	return TRUE;
}

5.如果可以是不是还能排序。。。
等等,不过功能更依赖与用户反馈

4.一个重要思想–“消费未来”

这个线性表的本质是一个工具。一个通用性工具。用户可以自定义数据类型USER_TYPE,但是正是由于是自定义,我们无法控制用户数据类型。所以在通过值查找元素下标时出现一个尴尬现象。
我们暂定的为int型可以相互比较。但如果是结构体,字符串等等,我们无法用同一种比较规则去应对不同的数据类型。
所以说最好,这个比较类型是让用户自己定义一个比较函数。我们来使用这个比较规则。

例如:int型,可以直接比较

boolean equalse(USER_TYPE one, USER_TYPE other);

boolean equalse(USER_TYPE one, USER_TYPE other) {
	return one == other;
}

所以你看到

int elementIndexOf(const LINEAR *head, USER_TYPE data, 
	boolean (*eq)(USER_TYPE, USER_TYPE))
	boolean (*eq)(USER_TYPE, USER_TYPE)这个就是调用用户自己数据类型的比较法则

这个是通过指向函数的指针,这个强有力的工具实现的。
关于这个指针后面会说到
所以,如果用户想要如何排序的话,我们也可以运用用户排序法则进行排序。

三、总结

1.人和动物的区别:人会使用工具,少有动物会使用工具(猩猩,乌鸦会)。
再区别:人会根据需求制造工具,人还会携带工具。
制造、携带工具使得先人们从森林法则中脱颖而出。

2.使用工具的人可以被替代,更换。但是能够制造工具的人,少了一个,就是一个领域的崩溃。就像语言就是一个工具。

3.消费未来。

笔者水平有限,目前只能描述以上问题,如果有其他情况,可以留言,有错误,请指教,有继续优化的,请分享,谢谢!
完整代码如下:
userType.h代码:

#ifndef _STICK_USERTYPE_H_
#define _STICK_USERTYPE_H_

typedef int USER_TYPE;
//这里可以根据用户个人要求修改其类型。

#endif

linear.h 代码:

#ifndef _STICK_LINEAR_H_
#define _STICK_LINEAR_H_

#include "userType.h"

typedef struct LINEAR {
	USER_TYPE *data;//用户需要的数据类型
	int capacity; //最大空间
	int count;//有效使用空间
}LINEAR;

typedef unsigned char boolean;
#define		TRUE		1    
#define		FALSE		0

#define		NOT_FOUND	-1

boolean initLinear(LINEAR **head, int capacity);
void destoryLinear(LINEAR **head);
int getCapacity(const LINEAR *head);
int getCount(const LINEAR *head);
boolean isLinearFull(const LINEAR *head);
boolean isLinearEmpty(const LINEAR *head);
boolean setElementAt (const LINEAR *head, int index, USER_TYPE data);
boolean getElemenAt(const LINEAR *head, int index, USER_TYPE *data);
boolean appendElementAt(LINEAR *head, USER_TYPE data);
boolean insertElementAt(LINEAR *head, int index, USER_TYPE data);
int elementIndexOf(const LINEAR *head, USER_TYPE data, 
	boolean (*eq)(USER_TYPE, USER_TYPE));
void clearLinear(LINEAR *head);
boolean removeElementAt(LINEAR *head, int index, USER_TYPE *data);

#endif

linear.c代码:

#include <stdio.h>
#include <malloc.h>

#include "linear.h"

//初始化线性表
boolean initLinear(LINEAR **head, int capacity) {
	if(NULL != *head ) {
		return FALSE;//如果控制头引进初始化过,返回
	}

 	*head = (LINEAR *)calloc(sizeof(LINEAR), 1); //申请一个控制头
 	(*head)->data = (USER_TYPE *)calloc(sizeof(USER_TYPE), capacity); //申请一个用户自定义存储空间
 	(*head)->capacity = capacity;
 	(*head)->count = 0;

 	return TRUE;//初始化成功
}
//销毁线性表
void destoryLinear(LINEAR **head) {
	if (NULL == head || NULL == *head) {
		return;
	}

	free((*head)->data);//释放自定义数据存储空间
	free(*head); //释放控制头空间
	*head = NULL; //指向控制头的指针销毁	
}

//得到最大空间量
int getCapacity(const LINEAR *head) {
	return head->capacity;
}
//得到有效使用空间量
int getCount(const LINEAR *head) {
	return head->count;
}
//判断线性表是否满了
boolean isLinearFull(const LINEAR *head) {
	/*if (head->count >= head->capacity) {
		return TRUE;
	}
	return FALSE;*/
	return head->count >= head->capacity;
}
//判断线性表是否为空
boolean isLinearEmpty(const LINEAR *head) {
	return head->count <= 0;
}
//修改线性表元素
boolean setElementAt (const LINEAR *head, int index, USER_TYPE data) {
	if (NULL == head || index < 0 || index >= head->capacity) {
		return FALSE;
	}
	head->data[index] = data; //修改

	return TRUE;
}
//得到指定位置的线性表元素
boolean getElemenAt(const LINEAR *head, int index, USER_TYPE *data) {
	if (NULL == head || index < 0 || index > head->count) {
		return FALSE;
	}
	*data = head->data[index]; //将指定指定位置的线性表元素复制下,可以用来展示

	return TRUE;
}
//追加线性表元素
boolean appendElementAt(LINEAR *head, USER_TYPE data) {
	//追加是插入到最后的插入数据
	return insertElementAt(head, head->count, data);
}
//插入线性表元素
boolean insertElementAt(LINEAR *head, int index, USER_TYPE data) {
	int i;
	if (NULL == head || isLinearFull(head)
		|| index < 0 || index > head->count ) {
		return FALSE;
	}
	
	for (i = head->count; i > index; i--) {
		head->data[i] = head->data[i-1]; // 从最后一个元素开始,依次向后移动,空出插入位置空间
	}
	head->data[index] = data; //实现插入
	++head->count; //有效元素增加

	return TRUE;//插入成功+
}
//查找某一元素
int elementIndexOf(const LINEAR *head, USER_TYPE data, 
	boolean (*eq)(USER_TYPE, USER_TYPE)) {
	int index;
	if (NULL == head || isLinearEmpty(head)) {
		return NOT_FOUND;
	}
	
	for (index = 0; index < head->count; index++) {
		if (eq(data, head->data[index])) {
			return index; //遍历已有的元素,找到返回其位置
		}
	}

	return NOT_FOUND; // 没找到
}
//清空线性表
void clearLinear(LINEAR *head) {
	head->count = 0;
}
//删除线性表某一元素
boolean removeElementAt(LINEAR *head, int index, USER_TYPE *data) {
	if (NULL == head || isLinearEmpty(head)
		|| index < 0 || index >= head->count) {
		return FALSE;
	}

	for (; index < head->count - 1; index++) {
		head->data[index] = head->data[index + 1]; //从最后一个元素,依次向前移动一位
	}
	head->count--;//有效元素个数减1

	return TRUE;
}

2020年02.18 家

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值