C语言数据结构学习笔记

这几天开始了对数据结构的学习,内容较多较杂,理解起来也颇为困难,故记录下学习中的笔记

什么是数据结构

数据结构是一门研究数据之间关系和操作 的学科,而非计算方法

数据结构的基本概念

  • 数据:所有能够输入到计算机中去描述失误的符号
  • 数据项:有独立含义的数据最小单位,也叫域
  • 数据元素:数据的基本单位也叫节点、记录
  • 数据结构:数据元素和数据关系的集合
  • 算法: 数据结构所具备的功能,解决特定问题的方法

数据结构的三个方面

  • 数据的逻辑结构
  • 数据的存储结构
  • 数据结构的运算

逻辑结构和存储结构
集合:数据元素同属于一个集体,但元素之间没有任何关系
线性结构:数据元素之间存在一对一关系
树形结构:数据元素之间存在一对多关系(倒悬树)
图型结构:数据元素之间存在多对多关系(地铁图)
数据的物理结构
顺序结构:数据元素存储在连续的内存中,用数据元素的相对位置来表示关系
优点:能够随机访问(想访问那个就访问那个) 访问效率极高(速度快)
缺点:空间利用率低,对内存要求比较高,插入、删除不方便
链式结构:数据元素存储在彼此独立的内存空间中,每个独立的元素也叫节点,每个数据元素中增加一个数据项用于存储其他元素的地址,用来表示元素之间的关系
优点:插入删除非常方便,空间利用率高
缺点:不能随机访问(只能由前到后逐个访问)

逻辑结构和物理结构的对应关系
表 顺序 链式
树 链式 顺序
图 顺序+链式
每种逻辑结构采用什么物理结构存储并没有明确的规定,通常根据实际的难易程度以及空间、时间方面的要求,来选择最合适的物理存储结构,也有可能采用多种物理结构复合存储

数据结构的和运算
1 建立数据结构 create
2 销毁数据结构 destory
3 清空数据结构 clean
4 数据结构排序 sort
5 删除元素 delete
6 插入元素 insert
7 访问元素 access
8 修改元素 modify
9 查询元素 query
10遍历数据结构 ergodic (show printf)

顺序表和链式表的实现

  • 顺序表:

    • 数据项
      1存储的内存首地址
      2表的容量
      3元素的数量
      
    • 运算:
        创建 销毁 清空 插入 删除 访问 修改 查询 排序 遍历
        注意
        	1 越界问题(不要越界)
        	2 要保持元素的连续性
      

      优点:支持随机访问,修改 查询 排序 效率高,大块连续的内存不易产生内存碎片

      缺点:对内存的要求比较高(内存连续、大块内存) 插入删除元素时不方便 且效率低

  • 链式表:

    • 元素的数据项:
      数据域:可以是各种类型的若干个数据项
      指针域:指向下一个元素
      由若干个元素通过指针域链接在一起形成链式表

    • 不带头节点:第一个元素存储的数据域就是有效的数据
      添加删除是可以修改头节点指针,参数需要使用二级指针
      同时需要获取到上一个节点的指针,而头节点没有上一个节点

    • 带头节点:第一个元素只代表头 不使用
      进行插入、删除操作时会比不带头节点的链表方便
      注意:其他操作时要从第二个节点开始

功能受限的表

对表的结构加以限制,形成特殊的表结构

  • 栈:只有一个进出口的表结构

    四种顺序栈
    top 初值 0 入栈 top++ 空增栈
    top 初值 -1 top++ 入栈 满增栈
    top 初值max-1 入栈 top-- 空减栈
    top 初值max top-- 入栈 满减栈
    先进后出

    • 顺序栈:

      • 数据域:
          存储元素的内存首地址
          栈的容量
          栈顶位置
        
      • 运算:
          创建、入栈、出栈、栈满、栈空、栈顶、销毁
        
    • 链式栈:

      • 数据域
          栈顶
          节点数量
        
      • 运算
          创建、销毁
        

      栈的应用:
      1 函数的调用(栈内存)
      2 生产者与消费者模型(栈当做仓库)
      3 表达式解析(中缀表达式后缀表达式)
      常见笔试面试题
      某序列为栈的入栈顺序,某序列是否是出栈顺序(边入边出)
      1 2 3 4 5
      3 1 2 4 5假!
      实现一个函数,判断序列b是否是a的出栈顺序
      bool is_popstack(int* a,int* b,size_t len);
      {
      // 创建一个栈
      // 按a的顺序入栈
      // 按b的顺序出栈
      // 最后判断如果栈为空,则b是a的出栈顺序
      }

bool is_popstack(int* a,int* b,size_t len)
{
	// 创建一个栈
	ArrayStack* stack = create_array_stack(len);
	// 按a的顺序入栈
	for(int i=0,j=0; i<len; i++)
	{
		push_array_stack(stack,a[i]);
		// 按b的顺序出栈
		int val = 0;
		while(top_array_stack(stack,&val) && val==b[j])
		{
			pop_array_stack(stack);
			j++;
		}
	}
	// 最后判断如果栈为空,则b是a的出栈顺序
	bool flag =  empty_array_stack(stack);
	destory_array_stack(stack);
	return flag;
}

队列:有两个进出口,一个端口进,另一个出,先进先出

  • 顺序队列:
    由一维数组+队头位置+队尾位置rear 组成,入队时rear+1,出队时front+1 为了让队列反复使用要把一维数组想象成环形.为了让rear和front加1后要用链表的容量求余
    rear = rear+1 % cal
    front = front+1 % cal
    如何判断队列为空: front == rear
    如何判断队列为满: front == rear+1
    代价就是要空一个位置不能用,或者再添加一个数据项用来标记是否是空还是满
    如何计算元素的数量:
    (rear-front+cal)%cal

  • 数据项:
      		存储元素的内存首地址
      		队头指针
      		队尾	即将入队的位置
      		容量			
    
  • 运算:创建、销毁、入栈、出栈、队空、队满、队头、队尾、元素数量
    
  • 链式队列
    由若干个节点组成的队列

  • 数据项:
      		队头指针
      		队尾指针
      		节点数量
    
  • 运算:创建、销毁、队空、(链式一般不满)	、入队、出队、队头、队尾、数量
      
      队列应用:
      	1 消息排队
      	2 树的层序遍历
      	3 图的广度优先遍历
      	4 封装线程池、数据池
    

    常见的笔试面试题:
    使用两个栈来模拟一个队列的功能
    从栈1到栈2一个不留
    如栈2不空则栈1不到栈2

装链表

尾添加效率低,非法下标的判断效率也非常低

  • 单链表
  • 数据项:
      头指针
      尾指针
      节点数量
    
  • 静态链表
  • 节点:
      数据域
      游标
    

静态链表的节点存储在连续的内存,通过游标来访问下一个节点
这种链表在插入删除时只需要修改游标的值,而不用申请、释放内存达到一种链式结构
但是也牺牲了随机访问的功能,是给没有指针的编程语言实现的一种单链表

  • 循环链表
    链表的最后一个节点的next不再指向NULL,而是指向头节点,这种链表叫单向循环链表
    单向循环链表,简称循环链表,它的好处是可以通过任意节点遍历整个链表
  • 双向链表
  • 节点:
      前驱指针
      数据域
      后驱指针
    
  • 数据项:
      头节点
      节点数量
    
  • 双向链表
    1 从任何节点都可以遍历整个列表
    2 已知节点的位置可以选择从前到后或从后到前,提高列表的查找速度
  • Linux内核链表
    链表的节点不能包含万物,就让万物包含节点 让外部的结构体包含链表 链表作为元素之一
  • 通用链表
    节点:
    指针域
    void* ptr
    运算:常用 功能+回调函数
    附上自己写的单链表逆序
//	逆序输出
void anti_show_list(Node* head)
{	
	Node* n1 = head;
	Node* n2 = head->next;
	for(Node* n3=NULL;NULL == n2;n2=n2->next)
	{
		n1->next = n3;
		n3=n1;
		n1=n2;
	}
}

数组与矩阵

数组:存储空间链接的表结构
矩阵:带二维信息的数据,一般使用二维数据来存储矩阵
特殊矩阵
	上三角形矩阵:
		[1][2][3][4]
		[ ][5][6][7]
		[ ][ ][8][9]
		[ ][ ][ ][x]
		压缩方法:用一维数组进行存储 (1 25 368 479x)
			数组长度 (n+1)*n/2
			对应关系 (j+1)×j/2+i
			i和j要满足 i<=j
	下三角形矩阵:
		[x][ ][ ][ ]
		[x][x][ ][ ]
		[x][x][x][ ]
		[x][x][x][x]
			数组长度 (n+1)*n/2
			对应关系 (i+1)*i/2+j
			i和j要满足 j<=i
	对称矩阵:沿着(0,0) (1,1) (2,2)...对称
		压缩方法:用一维矩阵存储把他当做上三角或下三角
	对角矩阵:(带状矩阵)沿着(0,0) (1,1) (2,2)...对角线两边有数据
		用一维数组存储
			数组长度 3*n-2
			对应关系 2*i+j 
			i和j要满足 abs(i-j) <= 1
	稀疏矩阵:有效信息不多,绝大多数都是无效信息,不需要存储,这种二维数组,没有特定的标准,全凭感觉
		压缩方式:
			三元组
				有三个数据项 行 列 值 构成一个整体存储在一维数组中
				
			//十字链表
	这些矩阵如果使用二维数组来存储的话,会非常浪费存储空间,为了节约空间,我们可以对这些矩阵进行压缩

你可能感兴趣的:(学习笔记,c语言)