数据结构复习-数组、广义表、递归、哈夫曼数/并查集

第5章 数组和广义表
数组定义:存储在连续内存单元的线性表,是一种随机存储结构。多维数组可以看作每个数据元素都是一个一维数组。

C/C++/PASCAL/BASIC等语言是行序存储,FORTRAN等是列序存储。

行序存储的数组a[m][n]:    loc(a[i][j]) = loc(a[0][0]) + (i*n + j) * k   --- k是每个元素所占的存储单元


特殊矩阵的压缩存储:

对称矩阵(元素关于主对角线对称,ai,j = aj,i),

三角矩阵(矩阵的上(下)三角中的元素均为常数,不包括对角线),

对角矩阵(所有非0元素集中在以对角线为中心的带状区域内)  

 把这些具有一定分布规律的元素压缩存储到一个空间中,进行一定的映射。


稀疏矩阵:只有当非0元素个数远小于总个数时,只存储非0元素;

1。 下标按照行有序的三元组顺序表存储结构

2。 十字链表,像编织一样的串起来。每一行/列均设置一个链表,方便行列搜索,降低复杂度。

//三元组
typedef struct
{ int r;   //row
   int c;  //column
   int d;  //data
}TupNode;

typedef struct
{
   int rows; 
   int cols;
   int nums;  //number of data
   TupNode data[MaxSize];
}TsMatrix;

//十字链表
typedef struct mtxn
{
int row;
int col;    //行号和列号
struct mtxn* right, * down;
union 
{
    int data;
    struct mtxn* link;     // 链表头节点指向列头节点链表的第一个行节点
}tag;
}


广义表:

数据元素相对有序,长度为最外层包含元素的个数,深度为所包含括弧的重数。可以递归,因为每个元素可以是原子数据也可以是子表数据

采用动态链式结构,添加一个tag域指示是否为子表。

//广义表
typedef struct lnode
{
    int tag;  // =0 标识原子数据
    union
   {
        int data;
        struct lnode* sublist;
   }val;
   struct lnode* link;

}


 
 

第6章 递归

在定义一个过程或函数时出现调用本过程或本函数的成分,成为递归。

数据的定义是递归的,数据结构是递归的,问题的求解方法是递归的。

其执行过程分为分解和求值,是函数嵌套调用的特殊情况,采用代码共享的方式,每次调用同一个函数的代码,每一次调用开辟栈空间,存放返回地址和参数,全部执行完后,栈应该为空。

#include <stdio.h>
#include <stdlib.h>
//recursive
/*
递归是一种分而治之的方法:
1.分析原问题,假设子问题
2.假设子问题可解,确定原问题的解
3.确定一个特殊情况,作为递归出口 
*/ 

//八皇后问题,皇后放在不同行,列,对角线
//place(k,n) 标识在1~k-1列上放好了,place(k+1,n),标志在1~k列上放好了,是子问题 
int cont =0;
int q[20];


void print(int n)
{
	int i;
	cont++;
	printf("第%d个解:",cont);
	for(i = 1; i<= n; i++)
	{
		printf("%d",q[i]);
	}
	printf("\n");
}

int find(int i,int k)
{
	int j;
	j = 1;
	while(j < k)
	{
		if(q[j] == i || abs(q[j] - i) == abs(j-k))
		{
			return 0;
		}
		j ++;
	}
	return 1;
}

void place(int k,int n)
{
	if(k > n)
	{
		print(n);
	}
	else
	{
		for(int i = 1; i<= n; i++)
		{
			//能放就放 
			if(find(i,k))
			{
				q[k] = i;
				place(k+1,n);
			}
		}
	}
}
int main()
{
	place(1,4);
	return 0;
} 


//哈夫曼树和并查集
//求最小带权路径长度,用于简化编码 
//判断两个元素之间的关系,利用集合合并,用代表元素标识集合的方法,不断合并子树,快速找出两个元素是否属于同一个集合 
#include <stdio.h>
#include <stdlib.h>

typedef struct{
	char data;
	double weight;
	int parent;
	int lchild;
	int rchild;
}HTNode;

//n个叶子节点,n-1个非叶子节点,更新每个非叶子节点的值 
void CreatHT(HTNode ht[],int n)
{
	int i,j,k,lnode,rnode;
	double min1,min2;
	for(int i=0;i<2*n-1;i++)
	{
		ht[i].parent = ht[i].lchild = ht[i].rchild = -1;
		
	}
	//构造哈夫曼树,lnode,rnode是最小权重的两个节点位置 
	for(i = n; i<2*n-1; i++)
	{
		min1 = min2 = 32767;
		lnode = rnode = -1;
		for(k=0; k <= i-1; k++)
		{
			//只在还没构造的节点中找 
			if(ht[k].parent == -1)
			{
			 
			if(ht[k].weight < min1)
			{
				min2 = min1;
				rnode = lnode;
				min1 = ht[k].weight;
				lnode = k;
			}
			else if(ht[k].weight < min2)
			{
				min2 = ht[k].weight;
				rnode = k;
			}
			}
		}
		ht[i].weight = ht[lnode].weight + ht[rnode].weight;
		ht[i].lchild = lnode;
		ht[i].rchild = rnode;
		ht[lnode].parent = i;
		ht[rnode].parent = i;
	}
}

//并查集
typedef struct node 
{
	int data;   //对应此人的编号 
	int rank;   //节点对应的秩 
	int parent; //节点对应的双亲节点 
} UFSTree;

void MAKE_SET(UFSTree t[])
{
	int i;
	for(i = 1; i<= N;i ++)
	{
		t[i].data = i;   //数据为此人的编号 
		t[i].rank = 0;   //秩初始化为0 
		t[i].parent = i; //双亲初始化指向自己 
	}
}

//在x所在子树中查找集合编号,递归直到找到祖先 
//改进:在找祖先root后,进行路径压缩,把该节点的所有祖先节点的父节点改为root 
int FIND_SET(UFSTree t[],int x)
{
	if(x!=t[x].parent)
		return (FIND_SET(t,t[x].parent));
	else
		return (x);
}

//O(log2 N)树的深度 
//合并的时候让较小秩的树根指向较大秩的树根 
void UNION(UFSTree t[],int x,int y)
{
	x = FIND_SET(t,x);
	y = FIND_SET(t,y);
	if(t[x].rank > t[y].rank)
	 	t[y].parent = x;
	else
	{
		t[x].parent = y;
		if(t[x].rank == t[y].rank)
			t[t].rank ++;
	}
}


你可能感兴趣的:(数据结构复习-数组、广义表、递归、哈夫曼数/并查集)