《数据结构与算法分析(Java语言描述)》读书笔记——1-6章,偏数据结构部分

1、最大子序列和(书2.4.3)

    联机算法(对已读入的数据,能给出结果)、流式计算

//数组全负结果为0
public int maxSubSum(int[] a) {
	int maxSum = 0;
	int thisSum = 0;
	for (int i = 0; i < a.length; i++) {
		thisSum += a[i];
		if (thisSum > maxSum) {
			maxSum = thisSum;
		} else if (thisSum < 0) {
			thisSum = 0;
		}
	}
	return maxSum;
}

 

2、二分查找(2.4.4)

    注意边界条件  low <= high

public int binarySearch(int[] a, int x) {
	int low = 0;
	int high = a.length - 1;
	while (low <= high) {
		int mid = ((high - low) >> 1) + low;
		if (a[mid] < x)
			low = mid + 1;
		else if (a[mid] > x)
			high = mid - 1;
		else
			return mid;
	}
	return -(low + 1);
}

 

3、欧几里得最大公约数算法(2.4.4)

    辗转相除法

public long gcd(long m, long n) {
	while (n != 0) {
		long rem = m % n;
		m = n;
		n = rem;
	}
	return m;
}

 

4、高效幂运算(2.4.4)

//未考虑n为负等情况,《剑指offer》上有各种情况的代码
public long pow(int x, int n) {
	if (n == 0)
		return 1;
	if ((n & 1) == 0)
		return pow(x * x, n >> 1);
	else
		return pow(x * x, n >> 1) * x;
}

 

5、后缀表达式(3.6.3 逆波兰表达式)

    将中序表达式转化为后缀表达式:数字直接输出,符号进栈,如果符号优先级≤栈顶符号优先级,弹出栈顶符号直到符号优先级>栈顶符号优先级,如果')'进栈则弹栈直到遇到'('。表达式扫描完毕后弹空栈。

    再用栈计算后缀表达式

    例如,a+b*c+(d*e+f)*g,后缀表达式为abc*+de*f+g*+。abc先输出,遇到第二个+,弹出*+,第二个+入栈。接着输出de,栈内为+(*,遇到+,弹出*,栈内为+(+;输出f;)入栈后,弹出+,栈内为+;输出g,栈内为+*,最后输出*+,得到后缀表达式。

    得到后缀表达式后,就不需要知道符号的优先级规则,用栈计算结果即可。

 

6、二叉树的遍历(4.2, 4.6)

    多叉树转化为二叉树:左儿子右兄弟原先最左的儿子为left,右侧相邻的兄弟节点成为right

//先序遍历
public void preTraversal(TreeNode root) {
	Stack<TreeNode> s = new Stack<>();
	if (root == null)
	        return;
	s.push(root);
	while (!s.isEmpty()) {
		root = s.pop();
		visit(root);
		if (root.right != null)
			s.push(root.right);
		if (root.left != null)
			s.push(root.left);
	}
}
//先序遍历
public void preTraversal(TreeNode root) {
	Stack<TreeNode> s = new Stack<>();
	while(root != null || !s.isEmpty()) {
		while(root != null) {
			s.push(root);
			visit(root);
			root = root.left;
		}
		if(!s.isEmpty()) {
			root = s.pop();
			root = root.right;
		}
	}
}
//中序遍历
public void inordTraversal(TreeNode root) {
	Stack<TreeNode> s = new Stack<>();
	while(root != null || !s.isEmpty()) {
		while(root != null) {
			s.push(root);
			root = root.left;
		}
		if(!s.isEmpty()) {
			root = s.pop();
			visit(root);
			root = root.right;
		}
	}
}
// 后序遍历 双栈法
public void preTraversal(TreeNode root) {
	if (root == null)
		return;
	Stack<TreeNode> s1 = new Stack<>();
	Stack<TreeNode> s2 = new Stack<>();
	s1.push(root);
	while (!s1.isEmpty()) {
		root = s1.pop();
		s2.push(root);
		if (root.left != null)
			s1.push(root.left);
		if (root.right != null)
			s1.push(root.right);
	}
	while (!s2.isEmpty())
		visit(s2.pop());
}
// 后序遍历
public void postTraversal(TreeNode root) {
	Stack<TreeNode> s = new Stack<>();
	s.push(root);
	TreeNode temp = root;
	while (!s.isEmpty()) {
		root = s.peek();
		if (root.left == null & root.right == null || root.left == temp && root.right == null || p.right == temp) {
			visit(root);
			temp = root;
			s.pop();
		} else {
			if (root.right != null)
				s.push(root.right);
			if (root.left != null)
				s.push(root.left);
		}
	}
}
// 树的高度
public int height(TreeNode root) {
	if (root == null)
		return 0;
	return 1 + Math.max(height(root.left), height(root.right));
}
// 反转树
public void reverseTree(TreeNode root) {
	if (root == null)
		return;
	Stack<TreeNode> s = new Stack<>();
	s.push(root);
	while (!s.isEmpty()) {
		root = s.pop();
		TreeNode temp = root.left;
		root.left = root.right;
		root.right = temp;
		if (root.left != null)
			s.push(root.left);
		if (root.right != null)
			s.push(root.right);
	}
}

 

7、AVL树(4.4)

    主要是L,R,LR,RL四种旋转。

    AVL树详解

 

8、B树,B+树,B*树(4.7)

    和二叉树相比,log函数的底更大,可以极大减少IO次数。

    B+树:(1)数据项在叶子上

               (2)根的儿子数在[2, M]之间(M阶B+树)

               (3)其余非叶子节点儿子数在[M/2, M]之间,非叶子节点节点中,关键字的个数与其子树的个数相同,不像B树中,子树的个数总比关键字个数多1个。关键字为子节点中的最小值或最大值。

                (4)叶子结点有指向下一个节点的指针,可以顺序查找(B树也有)这里之前写错了,B树不能顺序查找,想想也知道,B树中间层也有文件指针,如果可以顺序查找,next指针的处理会很麻烦。

                (5)B+树分裂、合并只影响原节点和父节点,不需要指向兄弟节点的指针(B*树有)

                (6)删除时优先与兄弟节点合并,不能合并再借一个儿子

    B树:关键字分布在整棵树中,不会像B+树一样重复出现

    B*树:块使用率为2/3,非叶子结点增加指向兄弟的指针(便于分裂,分裂时,兄弟节点未满则移入兄弟节点,已满则各移出1/3建立新节点)

    B+树比B树,B*树更适合做索引:B树每个节点都有文件指针,占用空间,B+树一次可以读入更多节点,可以减少IO次数,且B+树可以顺序查找,很适合数据库的范围查询。

    B树与B+树

 

9、散列解决冲突的办法(5.3, 5.4)

    分离链接法和开放定址法

    HashMap用分离链接法

    开放定址法有线性探测法、平方探测法、双散列、完美散列(用散列解决冲突)等,线性探测、平方探测等方法只能懒惰删除

 

10、其他

(1)包装类型是不可变的,平时强调的比较多的是public final class String,内部的char[]也是final的,包装类倒没怎么注意过。

注意和BigDecimal的区别,BigDecimal数值是不可变,a.add(b)不会改变a的值,应该写作a = a.add(b)

(2)数组是协变的,集合不是

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值