数据结构和算法分析整理

@skiery

数据结构算法分析第二版

1.引论

递归四原则:

1.基准情形:必须有无需递归就能得到的基准情形(如x=0,x=1)等情形下,直接得到结果。
2.不读阿奴推进:每次递归调用都必须使求解状况朝接近基准情形的方向推进。
3.设计法则:所有情况下的递归调用都能运行。
4.合成效益法则:求解同问题的同一个实例时,切勿在不同的递归调用中做重复性工作。(故斐波那契数列不建议递归)

2.算法复杂度分析

运行时间分析案例:

最大子序和

//暴力循环
int MaxSubsequenceSum0(const int a[], int N) {
	int ThisSum, MaxSum;
	MaxSum = 0;
	for (int i = 0; i < N; i++) {
		for (int j = i;j<N;j++)
		{
			ThisSum = 0;
			for (int k = i; k <= j; k++) {
				ThisSum += a[k];
			}
			if (ThisSum > MaxSum) {
				MaxSum = ThisSum;
			}
		}
	}
	return MaxSum;
}
//遍历循环每个子序
int MaxSubsequenceSum1(const int a[], int N) {
	int ThisSum,MaxSum;
	MaxSum = 0;
	for (int i = 0; i < N; i++) {
		ThisSum = 0;
		for (int j = i; j < N; j++) {
			ThisSum += a[j];
			if (ThisSum > MaxSum) {
				MaxSum = ThisSum;
			}
		}
	}
	return MaxSum;
}
//分治
static int MaxSubsequenceSum2(const int a[], int Left, int Right) {
	int MaxLeftSum, MaxRightSum;
	int MaxLeftBorderSum, MaxRightBorderSum;
	int LeftBorderSum, RightBorderSum;
	int Center;
	if (Left == Right) {
		if (a[Left] > 0)
		{
			return a[Left];
		}
		else {
			return 0;
		}
	}
	Center = (Left + Right) / 2;
	MaxLeftSum = MaxSubsequenceSum2(a, Left, Center);
	MaxRightSum = MaxSubsequenceSum2(a, Center + 1, Right);

	MaxLeftBorderSum = 0; LeftBorderSum = 0;
	for (int i = Center; i >= Left; i--) {
		LeftBorderSum += a[i];
		if (LeftBorderSum > MaxLeftBorderSum) {
			MaxLeftBorderSum = LeftBorderSum;
		}
	}
	MaxRightBorderSum = 0; RightBorderSum = 0;
	for (int i = Center + 1; i <= Right; i++) {
		if (RightBorderSum>MaxRightBorderSum)
		{
			MaxRightBorderSum = RightBorderSum;
		}
	}
	return max(max(MaxLeftSum, MaxRightSum), MaxLeftBorderSum + MaxRightBorderSum);
}

用的最多:

//动态规划
int MaxSubsequneceSumdy(const int a[], int N) {
	int ThisSum, MaxSum;
	ThisSum = MaxSum = 0;
	for (int i=0;i<N;i++)
	{
		ThisSum += a[i];
		if (ThisSum > MaxSum) {
			MaxSum = ThisSum;
		}
		else if (ThisSum < 0) {
			ThisSum = 0;
		}
	}
	return MaxSum;
}

3.线性表

3.1顺序表

特点:储存空间地址连续

数组实现:

//int a[];
int *a;
*a = 1;
*(a+1) = 2;

char* a = (char*)malloc(sizeof(char)*128);
//申请一个长度为128的字符串数组,返回头指针

数组插入,删除:

int a[10]={};
//delete 9th
for(int i=9-1;i<10-1;i++){
   a[i]=a[i+1];
}

3.2链表

特点:链式存储

3.2.1单链表

建立单链表:头插法、尾插法

typedef struct Node{
    int data;
    struct Node *next;
}Node,*LinkList;

//c++定义链表节点
class Node<int>{
    int item;
    Node<int> next;
    Node(int element){
        this.item = element;
        this.next = null;
    }
}

//尾部插入
Node *ptr = new Node(1);
Ntail->next = ptr;

//头部插入
Node *ptr = new Node(1);
ptr->next = head;//(head为头指针)

//中间插入
Node *ptr = new Node(1);
ptr->next = Npre->next;
Npre->next = ptr;

//按序号查找节点值
循环遍历所有结果再比较


//按值查找表节点
循环遍历

//求表长
循环遍历(一般情况下保存在头结点中)
3.2.2双链表
//双链表的插入
Node *ptr = new Node(1);
ptr->next = Npre->next;
ptr->pre = Nnext->pre;
Npre->next = ptr;
Nnext->pre = ptr;

//双链表的删除
Node *ptr; //需要删除的节点
Npre->next = ptr->next;
Nnext->pre = ptr->pre;
3.2.3循环链表
//判断是否为空
头结点指针是否等于头节点
if(head->next == head)

//插入删除同单链表相同

3.2.4静态链表

特点:需要提前分配连虚空间?????
??

4. 栈

4.1顺序栈

1.栈的指针指向栈顶 :为空时S.top = -1
2.栈空条件:栈空:S.top = -1;栈满:S.top = MaxSize-1;栈长:S.top+1
3.进栈:栈顶指针加1,再加元素
4.出栈:先取出元素,再指针减一

4.2链栈

所有操作都在该链表的表头进行

//入栈
Node *ptr = new Node(1);
ptr->next = stop;

//出栈
head = head->next;

4.3共享栈

特点:两个顺序栈共享一个一维数据空间
更有效利用空间??

int a[10];
a[0-5]; a[6-9];

5.队列

5.1顺序队列

//队列为空
Q.front == Q.rear == 0;

//进队
队尾先进值再指针加1

//出队
先取队头值再队头指针加1

5.2循环队列

与实际应用中使用的队列结构相仿

//初始
Q.front = Q.rear = 0;

//队空
Q.front = Q.rear;

//队列元素个数
(Q.front-Q.front+MaxSize)&MaxSize

5.3链式队列

链表实现的队列

5.4双端队列

双向队列

6.树

1对1为线性结构;
1对多为树型结构。

6.1二叉树

6.1.1二叉树顺序存储

用一组地址连续的存储单元,从上到下,从左到右存储完全二叉树上的结点元素。
完全二叉树:直接处理就行。

typedef struct TreeNode()

一般二叉树:空位置处加一个空指针(因此有些情况浪费大)

6.1.2二叉树的链式存储
typedef struct BitNode{
	int data;
	struct BitNode *lchild,*rchild;
}BitNode,*BitTree;

6.2二叉树的遍历

二叉树的遍历指按某种次序依次访问树中的每个节点,使得每个节点均被访问依次,而且仅被访问依次。
遍历方法分为:

遍历
先序遍历
递归
非递归
中序遍历
递归
非递归
后序遍历
非递归
递归
层次遍历
6.2.1先序遍历

先根、再先序遍历左子树、再先序遍历右子树

1.递归
void InOrder(BitTree T){
	if(T!=NULL){
		printf("%c",T->data);
		InOrder(T->lchild);//遍历递归左子树
		InOrder(T->rchild);//遍历递归右子树
		}
}
2.非递归
void PreOrder(BitTree T){
	InitStack(S);
	BitTree p=b; //工作指针
	while(p||!IsEmpty(S)){
		while(p){
			printf("%c",p->data);
			Push(S,p);
			p = p->lchild;
		}
		if(!IsEmpty(S)){
			p=Pop(S);
			p=p->rchild;
			}
	}
}
6.2.2中序遍历

先左子树,再访问根节点,再访问右子树

1.递归
void InOrder(BitTree T){
	if(T!=NULL){
		InOrder(T->lchild);//递归左子树
		printf("%c",T->data);
		InOrder(T->rchild);//递归右子树
		}
}
2.非递归
void MidOrder(BitTree T){
	InitStack(S);
	BitTree m;
	m = T;
	while(m||!IsEmpty(S)){
		while(m){
			Push(S,m);
			m=m->lchild;
		}
		if(!IsEmpty(S)){
			m=Pop(S);
			printf("%c",m);
			m = m->rchild;
			}	
	}
}
6.2.3后序遍历

先左子树,再右子树,最后根结点

1.递归
void InOrder(BitTree T){
	if(T!=NULL){
		InOrder(T->lchild);//递归左子树
		InOrder(T->rchild);//递归右子树
		printf("%c",T->data);
		}
}
2.非递归
void AftOrder(BitTree T){
	InitStack(S);
	BitTree a = T;
	BitTree r=NULL;
	while(a||!IsEmpty(S)){
			if(a){
				Push(S,a);
				a = a->lchild;
				}
			else{
				a = S.Top();
				if(a->rchild&&a->rchild!=r) a=a->rchild;
				else{
					Pop(S,a);
					printf("%c",a->data);
					r = a; //指向访问过的节点
					a = NULL; //使p为空从而继续访问栈顶
					}
				}
		}
}
6.2.4层序遍历

层序遍历过程:若树为空,直接返回;否则从树的第一层开始访问,从上而下逐层遍历,在同一层中,按从左到右的顺序对结点逐个访问。

出队–>访问–>左右孩子入队

void LevelOrder(BitTree T){
	InitQueue(Q);
	BitTree p;
	EnQueue(Q,T);
	while(!IsEmpty(Q)){
		DeQueue(Q,p);
		printf("%c",p->data);
		if(p->lchild!=NULL){
			EnQueue(Q,p->lchild);}
		if(p->rchild!=NULL){
			EnQueue(Q,p->rchild);}
		}
}

6.3线索二叉树

二叉链表示二叉树存在大量的空指针
复杂且偏,暂未整理

哈夫曼树和哈夫曼编码

高频出现项使用更短的编码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值