数据结构学习笔记(1.大O表示法和顺序表)

  最近在看国嵌唐老师的数据结构视频,觉得还不错,所以就把笔记记录下来

本节知识点:

1.数据之间的逻辑结构:
   集合结构:数据元素之间没有特别的关系,仅同属相同集合
   线性结构:数据元素之间是一对一的关系
   树形结构:数据元素之间存在一对多的层次关系
   图形结构:数据元素之间是多对多的关系
2.数据之间的物理结构
    顺序存储结构:将数据存储在地址连续的存储单元里
    链式存储结构:将数据存储在任意的存储单元里,通过保存地址的方式找到相关的数据元素
3.数据结构是相互之间存在一种或多种特定关系的数据元素的集合
4.程序 = 数据结构 + 算法
5.大O表示法:算法效率严重依赖于操作数量, 首先关注操作数的最高次项,操作数的估计可以作为时间和空间复杂度的估算,在没有特殊说明的时候, 我们应该分析复杂度的最坏情况
6.常见的复杂度类型:
大小关系:
7.线性表是零个或多个数据元素的集合,之间的元素是有顺序的,个数是有限的,数据类型必须相同。线性表包含两种存储方式,一种是顺序表,另一种链表。
8.对于线性表的使用是这样的:应该是在设计算法的时候,考虑算法中使用的数据,这些数据之间是什么关系的,如果是符合线性表特质的,就选择线性表作为数据结构。
9.顺序表与数组的关系:其实顺序表就是在数组的基础上构建的,本质跟数组是一样的,只是在数组的基础上增加了length长度,capacity容量等特性,然后补充了一些列,增、删、改、查的功能。
10. 我觉得链表比顺序表最大的优势,就在于链表的删除和插入要比顺序表简单的多,而且当线性表长度很大的时候很难开辟出整段的连续空间!!!最重要的是顺序表在创建的时候长度就固定了,再也改变不了了,而链表则可以根据情况动态增加,这一点是顺序表无论怎么样都不可能实现的!!!
 
顺序表的优点是:无需为线性表中的逻辑增加额外的空间,可以快速的通过下标的方式找到表中的合法位置。
11.线性表的常用操作:创建线性表、销毁线性表、清空线性表、将元素插入线性表、将元素从线性表中删除、获取线性表中某个位置的元素、获取线性表的长度

本节代码:

1.本节的代码是一个可以适合各种类型的顺序表,之所以能够适合各种类型,是因为它在顺序表中保存的是元素的地址(其实就是一个指针数组)。
2.代码中的描述顺序表的结构体中的元素介绍:length是顺序表中有元素的个数、capacity是顺序表的容量、node是顺序表的头地址(也是这个指针数组的头地址)、还有一个就是pos,pos是在删除和插入的时候使用的一个参数,它代表的是插入到顺序表位置的下标(数组的下标 是从0开始的 这个很要注意)。顺序表中有length个元素 下标是从0到length-1的。 要注意的是 操作顺序表不同功能函数的pos的允许范围是不一样的。
3.本节代码对于函数参数的合法性判断是极其重视的,这个规范是值得学习的。
4.本节代码中对于顺序表的操作函数,凡是外界输入的,和输出到外界的,都是void *类型的,这样就保证了只有在这些操作函数中才能去改变   描述顺序表的结构体里面的值,在其他文件的函数中接受到的都是void *类型,无法直接给这个结构体中的值进行改变,这样的封装,保证了代码的安全性。
5.对于本节代码最值得思考的地方,常见的顺序表是typedef一个A类型,然后在顺序表中定义一个这个A类型的数组和length顺序表元素个数,这个顺序表中是好多个A类型的顺序集合,占用空间的大小是sizeof(A)*capacity。而本节的顺序表中是好多个unsigned int *地址类型的顺序集合,表中只有地址,第一节省了顺序表的空间,第二这样可以变相的保存不同类型的数据,第三它实现了 顺序表(即数据结构) 和 我们打算利用的数据(即元素)的分离。例如:linux内核链表(一个双向循环链表)就是一套单独的链表体制,这个链表用在很多机制上面,它就是变相的存储了好多类型的数据,并且实现了链表和数据的分离。
所以在main.c中  数据要想保存在这个顺序表中  就应该先给这些数据开辟内存    因为顺序表中没有他们呆的地方   顺序表中只能保存他们的地址。
如图:
代码如下:
Seqlist.c:
/************************************************************************************ 
文件名:Seqlist.c
头文件:Seqlist.h 
时间: 2013/08/05 
作者: Hao 
功能:可以复用 带有增 删 改 查 功能的顺序表
难点:1.顺序表中存放的都是 各种数据的地址
      2.void *是用来隔离封装用的 保证顺序表结构体只能被特定的函数改变 
************************************************************************************/
#include <stdio.h>
#include <malloc.h>
#include "Seqlist.h"

typedef unsigned int TSeqListNode;//这个顺序表中存放的是 各种数据的地址 所以用unsigned int 
typedef struct str_SeqList
{
	int length;//顺序已用的长度 
	int capacity;//顺序表的总容量 
	TSeqListNode* node;//这个指针是用来在顺序表中游走读取数据用的 
}TSeqList;  //定义描述顺序表的结构体 

/************************************************************************************ 
函数名:   Creat_SeqList
函数功能: 创建一个容量为capacity的顺序表 
参数:     int capacity 创建顺序表中成员的个数 即顺序表容量
返回值:   void* ret 如果返回NULL 说明创建顺序表失败
                     如果返回ret 说明创建顺序表成功  且ret为描述顺序表的结构体 
************************************************************************************/
SeqList* Creat_SeqList(int capacity)
{
	TSeqList* ret = NULL;
	/*进入函数 第一点是先判断传人参数的合法性*/
	if(capacity >= 0)
	{
		/*给顺序表开辟空间*/
		ret=(TSeqList* )malloc(sizeof(TSeqList)+sizeof(TSeqListNode)*capacity);
		if(NULL!=ret)//空间开辟成功   给描述顺序表的结构体 赋值 
		{
			ret->capacity=capacity;
			ret->length=0;
			ret->node=(TSeqListNode* )(ret+1);//把真正顺序表的地址赋给 node 
		}
	}
	else
	{
		ret = NULL;
	} 
	return (SeqList*)(ret);
} 

/************************************************************************************ 
函数名:   Destroy_SeqList
函数功能: 销毁顺序表   free开辟的内存 
参数:     void* list 描述顺序表结构体指针
返回值:   void 
************************************************************************************/
void  Destroy_SeqList(SeqList* list)
{
	free(list);
}

/************************************************************************************ 
函数名:  Get_Seqlist_Length
函数功能:获得顺序表 现在的大小
函数参数:void* list 描述顺序表结构体指针
函数返回值:int ret  成功返回length
                     失败返回-1 
************************************************************************************/
int Get_Seqlist_Length(SeqList* list)
{
	int ret;
	TSeqList *Tlist=(TSeqList* )list;
	/*函数参数合法性检测*/
	if(NULL != Tlist)
	{
		ret=Tlist->length;
	} 
	else
		ret=-1;
	return ret;
}

/************************************************************************************
函数名:  Get_Seqlist_Capacity
函数功能:获得顺序表 的容量 
函数参数:void* list 描述顺序表结构体指针
函数返回值:int ret  成功返回capacity 
                     失败返回-1 
************************************************************************************/
int Get_Seqlist_Capacity(SeqList* list)
{
	int ret;
	TSeqList *Tlist=(TSeqList* )list;
	/*函数参数合法性检测*/
	if(NULL != Tlist)
	{
		ret = Tlist->capacity;
	} 
	else
		ret=-1;
	return ret;
}

/************************************************************************************ 
函数名:  Clean_Seqlist_Length
函数功能:清空顺序表  其实就是给length=0; 
函数参数:void* list 描述顺序表结构体指针
函数返回值:int ret  成功返回0
                     失败返回-1 
************************************************************************************/
int Clean_Seqlist_Length(SeqList* list)
{
	int ret;
	TSeqList *Tlist=(TSeqList* )list;
	/*函数参数合法性检测*/
	if(NULL != Tlist)
	{
		Tlist->length=0;
		ret=0;
	} 
	else
		ret=-1;
	return ret;
}

/************************************************************************************
函数名:  Seqlist_Add
函数功能:顺序表中有length个数据  在下标为pos的位置上 插入数据node  所以pos是从0开始的 length是从1开始的 
参数:      SeqList* list描述顺序表的结构体地址   SeqListNode* node插入顺序表的数据的地址  
		   int pos插入顺序表的位置   pos的范围是从0(此时在顺序表头部插入)开始  到length(此时就是在顺序尾部插入)
		    总共是length+1个位置 
返回值 :  返回1 说明插入数据成功  返回0 说明插入数据失败
************************************************************************************/
int Seqlist_Add(SeqList* list, SeqListNode* node ,int pos)
{
	/*参数合法性检测*/
	TSeqList *Tlist=(TSeqList* )list;
	int ret = (NULL != list);
	int i;
	ret=ret && (pos >= 0);
	ret=ret && (Tlist->length+1 <= Tlist->capacity);  //判断再插入一个数据的时候  length有没有超过 capacity 
	if(1 == ret)
	{
		if(pos >= Tlist->length)//如果插入的位置pos比 length大的话 默认把length+1赋值给pos 
		{
			pos = Tlist->length;
		}
		for(i=Tlist->length;i>pos;i--)
		{
			Tlist->node[i]=Tlist->node[i-1];
		} 
		Tlist->node[i]=(TSeqListNode)node; //把要插入的地址强制类型转换成 unsigned int* 
		Tlist->length++;
	} 
	return ret;//返回1 说明插入数据成功  返回0 说明插入数据失败 
}	

 
/************************************************************************************
函数名:   Get_Node
函数功能:找到顺序表中下标为pos的值  
参数:    pos插入顺序表的下标   pos的范围是从0到length-1   
          SeqList* list描述顺序表的结构体地址
返回值:  void* ret 找到pos为下标的那个值
        如果成功返回pos为下标的那个值   如果失败  返回NULL
************************************************************************************/

SeqListNode* Get_Node(SeqList* list, int pos)
{
	TSeqList* Tlist=(TSeqList* )list;
	SeqListNode* ret=NULL;
	if( (NULL!=Tlist) && (pos>=0) && (pos<Tlist->length) )
	{
		ret=(SeqListNode* )Tlist->node[pos]; //强制类型转换成void*  
	}
	return ret;
} 

/************************************************************************************
函数名:   Del_Node
函数功能:找到顺序表中下标为pos的值  并且删除它 
参数:    删除pos为下标的值   pos的范围是从0到length-1   
          SeqList* list描述顺序表的结构体地址
返回值:  void* ret 
          如果成功返回pos为下标的那个值   如果失败  返回NULL 
************************************************************************************/
SeqListNode* Del_Node(SeqList* list, int pos)
{
	TSeqList* Tlist=(TSeqList* )list;
	SeqListNode* ret=NULL;
	int i;
	if( (NULL!=Tlist) && (pos>=0) && (pos<Tlist->length) )
	{
		ret=(SeqListNode* )Tlist->node[pos];
		for(i=pos+1; i<Tlist->length; i++)
		{
			Tlist->node[i-1]=Tlist->node[i];
		}
		Tlist->length--;
	}
	return ret;
}



Seqlist.h:
#ifndef __Seqlist__
#define __Seqlist__

typedef void SeqList;  //是用来封装 使顺序表结构体 不被外界改变 只可被Seqlist.c文件中的函数改变
                       //因为 这些函数 对外的接口 都是void*  
typedef void SeqListNode;//SeqList 是用来表示 顺序表的    SeqListNode是用来表示顺序表 中变量的 

SeqList* Creat_SeqList(int capacity);
void  Destroy_SeqList(SeqList* list);
int Get_Seqlist_Length(SeqList* list);
int Get_Seqlist_Capacity(SeqList* list);
int Clean_Seqlist_Length(SeqList* list);
int Seqlist_Add(SeqList* list, SeqListNode* node ,int pos);
SeqListNode* Get_Node(SeqList* list, int pos);
SeqListNode* Del_Node(SeqList* list, int pos); 

#endif

main.c:
#include <stdio.h>
#include <stdlib.h>
#include "Seqlist.h"
int main(int argc, char *argv[])
{
	SeqList* My_SeqList = NULL;
	int a = 10;
	int b = 5;
	int c = 3;
	int d = 6;
	int e = 1;
	int *p = NULL;
	int i = 0;
	My_SeqList = Creat_SeqList(5);
	if( NULL != My_SeqList )
	{
			Seqlist_Add(My_SeqList, &a ,0);
			Seqlist_Add(My_SeqList, &b ,0);
			Seqlist_Add(My_SeqList, &c ,0);
			Seqlist_Add(My_SeqList, &d ,0);
			Seqlist_Add(My_SeqList, &e ,0);
			
			for(i=0; i<Get_Seqlist_Length(My_SeqList); i++)
			{
				p=Get_Node(My_SeqList, i);
				printf("%d\n",*p);
			}
			
			Del_Node(My_SeqList, 3);
			for(i=0; i<Get_Seqlist_Length(My_SeqList); i++)
			{
				p=Get_Node(My_SeqList, i);
				printf("%d\n",*p);
			}
			
	} 
	Clean_Seqlist_Length(My_SeqList);
	Destroy_SeqList(My_SeqList);
	return 0;
}


仔细观察下面错误代码,test_main.c:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "Seqlist.h"

typedef struct student
{
	int student_num;
	char name[30];
	char sex[20];
	int age;
}str;
int main()
{
	str* str1;
	SeqList* slist=NULL;
	int i=0;
	int age=0;
	slist=Creat_SeqList(50);
	if(NULL == slist)
	{
		printf("malloc error!!!\n");
		return -1;
	}
	for(i=0; i<3; i++)
	{
		put_student(slist, str1);
	}
	
	printf("输入你要删除的年龄:\n");
	scanf("%d",&age);
	printf("\n");
	find_student(slist, str1, age);
	get_student(slist, str1);
	
	destroy_student(slist, str1);
	Clean_Seqlist_Length(slist);
	Destroy_SeqList(slist);
	return 0;
}

int put_student(SeqList* slist, str* str1)
{ 
	int num;
	int ret=(NULL != str1);
	if(1 == ret)
	{
		ret=ret && Seqlist_Add(slist, (str* )malloc(sizeof(str)*1) ,50);
		num = Get_Seqlist_Length(slist);
		str1 = (str* )Get_Node(slist, num-1);
		printf("请输入学生学号:\n"); 
		scanf("%d",&str1->student_num);
		printf("请输入学生姓名:\n");
		scanf("%s",str1->name);
		printf("请输入学生性别:\n");
		scanf("%s",str1->sex);
		printf("请输入学生年龄:\n");
		scanf("%d",&str1->age);
		printf("\n"); 
	}		
	else
	{
		ret = 0;
	}
	return ret;
}

int get_student(SeqList* slist, str* str1)
{
	int ret=(NULL != str1);
	int i=0;
	if(1 == ret)
	{
		for(i=0; i<Get_Seqlist_Length(slist); i++)
		{
			str1 = (str*)Get_Node(slist, i);
			printf("学生学号:%d\n",str1->student_num);
		
			printf("学生姓名:%s\n",str1->name);
			
			printf("学生性别:%s\n",str1->sex);
			
			printf("学生年龄:%d\n",str1->age);
		}
	}		
	else
	{
		ret = 0;
	}
	return ret;
}

int destroy_student(SeqList* slist, str* str1)
{
	int ret=(NULL != str1);
	int i=0;
	if(1 == ret)
	{
		for(i=0; i<Get_Seqlist_Length(slist); i++)
		{
			str1 = (str*)Get_Node(slist, i);
			free(str1);
		}
	}		
	else
	{
		ret = 0;
	}
	return ret;
}

int find_student(SeqList* slist, str* str1, int age)
{
	int ret=(NULL != str1);
	int i=0;
	int num=0;
	if(1 == ret)
	{
		num=Get_Seqlist_Length(slist);
		for(i=0; i<num; i++)
		{
			str1 = (str*)Get_Node(slist, i);
			if(str1->age == age)
			{
				Del_Node(slist, i);
				num=Get_Seqlist_Length(slist);
				i--;
			}
		}
	}		
	else
	{
		ret = 0;
	}
	return ret;
}





已标记关键词 清除标记
相关推荐
简介 第1章综述 数据结构和算法能起到什么作用? 数据结构的概述 算法的概述 一些定义 面向对象编程 软件工程 对于C++程序员的Java Java数据结构的类库 小结 问题 第2章数组 Array专题Applet Java中数组的基础知识 将程序划分成类 类接口 Ordered专题applet 有序数组的Java代码 对数 存储对象 大O表示法 为什么不用数组示一切? 小结 问题 实验 编程作业 第3章简单排序 如何排序? 冒泡排序 选择排序 插入排序 对象排序 几种简单排序之间的比较 小结 问题 实验 编程作业 第4章栈和队列 不同的结构类型 栈 队列 优先级队列 解析算术达式 小结 问题 实验 编程作业 第5章链 链结点(Link) LinkList专题Applet 单链 查找和删除指定链结点 双端链的效率 抽象数据类型 有序链 双向链 迭代器 小结 问题 实验 编程作业 第6章递归 三角数字 阶乘 变位字 递归的二分查找 汉诺(Hanoi)塔问题 归并排序 消除递归 一些有趣的递归应用 小结 问题 实验 编程作业 第7章高级排序 希尔排序 划分 快速排序 基数排序 小结 问题 实验 编程作业 第8章二叉树 为什么使用二叉树? 树的术语 一个类比 二叉搜索树如何工作 查找节点 插入一个节点 遍历树 查找最大值和最小值 删除节点 二叉树的效率 用数组示树 重复关键字 完整的tree.java程序 哈夫曼(Huffman)编码 小结 问题 实验 编程作业 第9章红-黑树 本章讨论的方法 平衡树和非平衡树 使用RBTree专题applet 用专题applet做试验 旋转 插入一个新节点 删除 红-黑树的效率 红-黑树的实现 其他平衡树 小结 问题 实验 第10章2-3-4树和外部存储 2-3-4树的介绍 Tree234专题applet 2-3-4树的Java代码 2-3-4树和红-黑树 2-3-4树的效率 2-3树 外部存储 小结 问题 实验 编程作业 第11章哈希 哈希化简介 开放地址法 链地址法 哈希函数 哈希化的效率 哈希化和外部存储 小结 问题 实验 编程作业 第12章堆 堆的介绍 Heap专题applet 堆的Java代码 基于树的堆 堆排序 小结 问题 实验 编程作业 第13章图 图简介 搜索 最小生成树 有向图的拓扑排序 有向图的连通性 小结 问题 实验 编程作业 第14章带权图 带权图的最小生成树 最短路径问题 每一对顶点之间的最短路径问题 效率 难题 小结 问题 实验 编程作业 第15章应用场合 通用数据结构 专用数据结构 排序 图 外部存储 前进 附录A运行专题applet和示例程序 专题applet 示例程序 SunMicrosystem软件开发工具集 重名的类文件 其他开发系统 附录B进一步学习 数据结构和算法 面向对象程序语言 面向对象设计(OOD)和软件工程 附录C问题答案 第1章,综述 第2章,数组 第3章,简单排序 第4章,栈与队列 第5章,链 第6章,递归 第7章,高级排序 第8章,二叉树 第9章,红-黑树 第10章,2-3-4树和外部存储 第11章,哈希12章,堆 第13章,图 第14章,带权图
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页