您的位置:首页 > 理论基础 > 数据结构算法

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

2015-03-23 19:56 302 查看
第5章 数组和广义表

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

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

行序存储的数组a[m]
: 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 ++;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: