CS61B - Lec 1-4

絮叨一下

大名鼎鼎的CS61B。开个博客记录一下一些值得注意的点。

目前感受如下:

  1. Josh Hug is the best teacher! 我一直以为聪明人不容易出好老师,因为他们觉得一切都很简单。。。碰到他发现我错了,他能理解很多学生会遇到的困难,懂得我们的心理,而且真的是一个有趣又可爱的人。
  2. Not just a data structure class. 以java为基础,各种数据结构都会手把手建一个类来实现,顺带入门了java,完全搞明白了面向对象编程思想。
  3. Coding philosophy. 跟老师一起建数据结构学了一些他的好习惯。

写于不知能否去.不知要不要转码.不知要不要读博的北美20fall准备期.

课程视频来源于b站,相关资料:https://sp18.datastructur.es/index.html

Lec1, Lec2 - Intro

Lec1: 课程安排,课程注意事项,为什么学这门课,不多说了
Lec 2重点

  1. java基于类的编写方式
  2. static和non-static(instance) members区别:外部需不需要通过对象调用,有了static关键字无需定义对象,直接通过类名.变量/方法调用。

Lec 3 - References and Recursion

这一章彻底让我搞懂了C++以前莫名其妙的引用概念(个人感觉这个词翻译的不好)。

引用详解

  • 定义

java中有8种原始数据类型(primitive type),包括byte, short, int, long, float, double, boolean, char,其他类型,如数组,类都称之为reference type。
是不是觉得有一堆特别熟悉的名词。。。

  • 一条真理

y = x,意为y拷贝了所有变量x中存储的bits。

  • 分析

原始数据类型,变量存储的是大小,拷贝之后,x,y为两独立变量。
reference type,每次声明时,java会自动分配64位存储空间。每当用new进行初始化时,new会返回一个64为数据,记录内存地址,拷贝进变量。所以,此时y和x在同一地址,一个改变对所有都生效。
在这里插入图片描述
在这里插入图片描述
很显然x不变,walrus will lose 100lbs

扫描二维码关注公众号,回复: 10893301 查看本文章

数组初始化几种方式

比较繁琐,这里记下方便找

int[] x = new int[5];
int[] x = null;
int[] x = new int[]{0, 1, 2};
int[] x = {0, 1, 2};

IntList

public class IntList {

	public int first;
	public IntList rest;

	public IntList(int f, IntList l) {
		first = f;
		rest = l;
	}

	public int size() {
		if (rest == null) {
			return 1;
		}
		return 1 + rest.size();
	}

	public int iterativeSize() {
		IntList l = this;
		int num = 0;
		while (l != null) {
			num += 1;
			l = l.rest;
		}
		return num;
	}

	/* Return the ith item of this IntList. */
	/* Recursion. */
	public int get(int i) {
		if (i == 0) {
			return first;
		}
		return rest.get(i - 1);
	}
    
    /** Iterative */
    /*
	public int get(int i) {
		IntList l = this;
		for (int n = 0; n < i; n += 1) {
			l = l.rest;
		}
		return l.first;
	}
	*/

	/* All values incremented by x; do not change values in l */

	public static IntList incrList(IntList l, int x) {
		if (l == null) {
			return null;
		}
		IntList res = new IntList(l.first + x, null);
		IntList ptr = res;
		l = l.rest;

		while (l != null) {
			ptr.rest = new IntList(l.first + x, null);
			ptr = ptr.rest;
			l = l.rest;
		}
		return res;
	}

	/* All values in l incremented by x; not allowed to use 'new' */

	public static IntList dincrList(IntList l, int x) {
		IntList ptr = l;
		while (ptr != null) {
			ptr.first += x;
			ptr = ptr.rest;
		}
		return l;
	}


	public static void main(String[] args) {
		IntList l = new IntList(15, null);
		l = new IntList(10, l);
		l = new IntList(5, l);
		System.out.println(l.get(2));
		System.out.println(IntList.incrList(l, 2).get(2));
		System.out.println(l.get(2));

	}
}

链表类的建立。注意其中有很多recursive的方法,包括建立初始化也是recursive方式。

l = new IntList(10, l);

此句意为addFirst。

Lec4 - Node based lists

上节末尾的IntList有改进的空间。
建完之后会发现,对用户不太友好,用户需要有recursive的思想,以及丰富的references知识。
将IntList称之为“naked"链表。

IntList to SLList

在这里插入图片描述
如图,将IntList更名为IntNode,代表一个节点,将变量rest更名为next。IntNode作为新的SLList的nested class。为什么这么做呢?

首先,SLList更容易初始化。

SLList X = new SLList(5);
IntList Y = new IntList(5, null);

这好像没什么。

然后,如果想要向链表里加入数据,IntList是这样操作的。

Y = new IntList(6, Y);
Y = new IntList(7, Y);

比较绕而且麻烦。而SLList是这样:

X.addFirst(6);
X.addFirst(7);

那为什么不在IntList里加入addFirst()呢?

public class IntList {

	public int first;
	public IntList rest;

	public IntList(int f, IntList l) {
		first = f;
		rest = l;
	}

	public void addFirst() {
		//this = new IntList(x, this);
	}
}

仔细看了一会,发现只能这么搞,但是肯定编译不通过啊没办法。除了this以外,没有变量能表明当前指针的位置,只有指向下一个数据的rest,所以不好搞。
在这里插入图片描述
IntList user want to have variables that point to the middle of the IntList,就是我上面说的意思。SLList中的IntNode就可以表明当前位置。

Private关键字

在这里插入图片描述
如图,如果开放first变量的权限变为public,那么用户有时候就会瞎改first,出错。为避免用户瞎闹腾,我们用private关键字把first封起来。同样,nested类IntNode也没必要,直接private。

Static关键字另一层含义

在这里插入图片描述
前文说到static方法可以无需定义对象直接通过类名调用,为什么会这样呢?
因为static关键字真实含义是,本方法不会用任何类中变量。既然各个对象中特有的变量值与我无关,则无需定义对象也可调用。
所以,可以把IntNode定义成static方法,然而因为是private,外面也不会动他,不加也问题不大,据说这样会省内存。

加入addLast()与Size()

addLast()比较简单

public void addLast(Item x) {
		IntNode p = first;

		while (p.next != null) {
			p = p.next;
		}
		p.next = new IntNode(x, null);
		size += 1;
	}

size()用了很tricky的迭代方式

/** Return the size of a SLList. (recursion) */
	/* Return the size of the list that starts at p. */
	private static int size(IntNode p) {
		if (p.next == null) {
			return 1;
		}
		return 1 + size(p.next);
	}

	public int size() {
		return size;
	}

然而看着好看,无卵用。这个size()太慢了。现在有SLList了啊,只需要建立一个size变量,每次加入或减少数据,size相应地变化,所以:

public int size() {
		return size;
	}

要学会类的思想。

改进addLast()

addLast()此时仍有一个小bug

SLList s = new SLList();
s.addLast(5);

这样就坏掉了。因为对象为空时first也为空,没有next,无法往后遍历。这咋整呢?
加判断?那就不太整洁了。这里提出了invariance的思想。
无论链表是否为空,属性都应相同。
答案是建立sentinel node,代表链表头,下一个才是数据。

/** Constructor. */
	/* The first item is sentinel.next */
	private IntNode sentinel;
	private int size;

	/* Create an empty list. */
	/* Just set the item of sentinel to null */
	public SLList() {
		sentinel = new IntNode(null, null);
	}
	/* Init an list with one item. */
	public SLList(Item x) {
		sentinel = new IntNode(null, null);
		sentinel.next = new IntNode(x, null);
		size = 1;
	}

这样就解决了addLast的问题。
在这里插入图片描述
这一节信息量还是很大的。

发布了20 篇原创文章 · 获赞 0 · 访问量 170

猜你喜欢

转载自blog.csdn.net/fourier_transformer/article/details/105170736