20172314 2018-2019-1《程序设计与数据结构》第二周学习总结
教材学习内容总结
第三章 集合概述-栈
集合
-
集合是一种聚集组织了其他对象的对象
-
线性集合:元素按直线方式组织的集合 非线性集合:元素按非直线方式(例如网状组织或层次组织)组织的集合。
-
集合中的元素通常是按照他们添加到集合中的顺序,或者是按元素之间的某种内在关系来组织的。
抽象数据类型
- 集合是一种隐藏了实现细节的抽象。
- 数据类型:是一组值及作用于这些数值上的各种操作。(例如整数数据类型就包括数值及这些数值之间的加减乘除操作。)
- 抽象数据类型:是一种在程序设计语言中尚未定义其值和操作的数据类型。
- 数据结构是一种用于实现集合的基本编程结构。
Java集合API
- Java程序设计语言的部分用于支持软件开发的类库是以API(应用程序编程接口)形式存在的。
- Java集合API是一个类集,表示了一些特定类型的集合,这些类的实现方式各不相同。
- Java集合API提供的集合1.可能只是我们所需集合的一个子集2.可能并没有按照我们所希望的方式来实现这些集合3.对软件开发的研究要求我们深入理解集合设计以及用数据结构实现集合所涉及的一些问题。所以我们仍需学习如何设计实现集合。
栈集合
-
通常垂直绘制栈,并把栈的末端称为栈的顶部。
-
栈的常见操作:
- push:添加一个元素到栈的顶部
- pop:从栈的顶部移出一个元素
- peek(有时称为top):查看栈顶部的元素
- isempty:确定栈是否为空
- size:确定栈的元素数目
-
编程人员选择的数据结构,应与需要进行数据管理的类型相适应。
主要的面向对象概念
- 类型兼容性:把一个对象赋给引用的特定赋值是否合法。例如
String x = new Integer(10)
就是不合法的。 - 把数据储存在集合中可以利用继承和多态的概念,以创建可以储存任意类型的对象的集合。
继承与多态
- 多态引用是一个引用变量,他可以在不同地点引用不同类型的对象。继承可以创建一个类层次,一个变量可以用于指向与之相关的任何对象。
泛型
-
泛型指可以定义一个类,以便他能存储、操作和管理在实例化之前没有指定是何种类型的对象。
-
把Box类定义为可以储存泛型T
class Box<T> } //用于管理类型T的对象的声明和代码 }
-
实例化Box类时,需要用具体的类来替换T来实例化它
Box<Widge> box1 = new Box<Widge>
Box<Gadget> box2 = new Box<Widge>
box1和box2只能分别储存Widge和Gadget类型
-
泛型(T)不能被实例化,他只是一个占位符,允许我们去定义管理特定类型的对象的类,且只有当该类被实例化时,才创建该类型的对象。
使用栈计算后缀表达式
-
当遇到操作符弹出操作数时,首先弹出的是第二个操作数,第二个弹出的是第一个操作数,这种顺序对于加法和乘法无影响,但对减法除法有影响。
-
后缀表达式不合法的情况:
- 遇到操作符时栈中没有两个操作数。
- 当表达式中的符号用完后,栈中的数不止一个。
Javadoc
- doc注释以 /** 开始,以 */ 结束
- Javadoc是Java代码添加注释的官方标准
- @author标识代码的程序员
@version指定代码的版本号
@return表明由该方法返回的值
@param标识传递给该方法的每个参数
异常
- 异常就是一个对象,它定义了一种非正常或错误的情况。异常由程序或运行时环境抛出,可以按预期的被捕或被正常处理。
- 错误与异常类似,只不过错误往往表示一种无法恢复的情况,且不必去捕获它。
栈ADT
Java接口定义了一个抽象方法集,有助于把抽象数据类型的概念与其实现分隔开来。
-
通过使用接口名作为返回类型,方法就不会局限于实现栈的任何特定类。
-
栈接口被定义为StackADT
,表示作用于泛型T。在该接口的方法中,各种参数和返回值的类型往往用泛型T来描述。当实现该接口时,将会用某种数据类型来替换泛型T。 -
栈接口
-
```public interface StackADT <T>```
其中interface是保留字,StackADT是接口名,
是泛型参数。 -
取消操作可以用栈来实现,名为drop-out,将取消的操作压入栈中,或退回弹出,当达到限制时,栈底的元素将被从栈中丢掉。
用数组实现栈
-
集合操作的实现不应该影响到用户与该集合进行交互的方式。
-
创建可储存number个元素的数组,其容量为number
Object[] collection = Object[number]
-
当元素添加到一个满的数据结构中时:
- 如果集合为满,抛出一个异常
- 实现add操作,返回一个可由用户检查的状态标识符,以便查看该add操作是否成功。
- 当需要时可扩展集合的容量,这样集合永远也不会满。
ArrayStack类
-
出于运行效率的考虑,基于数组的栈实现总是使栈底位于数组的索引0处。
-
栈的数组实现可以通过4个假设来实现
- 该数组是一个对象引用的数组(数据类型在实例化时确定)
- 栈底总是在数组的索引0处
- 栈的元素是按顺序并连续地储存在数组中
- 有一个整数变量top,保存了紧跟栈顶元素后的数组索引号
-
构造函数
*
/*使用默认容量创建一个空栈*/ public ArryStack() { top = 0; stack = (T[]) (new Object[DEFAULF_CAPACITY]); /*实例化了一个Object数组,然后把他转换为一个泛型数组。这里会产生一个未检验类型转换的编译时的警告,可用@SuppressWarnings("uncheched")禁止警告。*/ }
``` /*使用指定容量创建一个空栈,参数initialCapacity表示的是指指定容量*/ public ArrayStack (int initialCapacity) { top = 0; stack = (T[]) (new Object[initialCapacity]) } ```
-
泛型(包括泛型数组)不能被实例化,这就是为什么我们必须创建一个储存Object引用的数组,然后把它转换成泛型数组的原因。
-
创建一个泛型数组
stack = (T[]) (new Object[initialCapacity]);
push
public void push(T element)
{
if (size() == stack.length)
expandCapacity();
stack[top] = element;
top++;
}
pop
public T pop() throws EmptyCollectionException
{
if (isEmpty())
throw new EmptyCollectionException("stack");
top--;
T result = stack[top];
stack[top] = null;
return result;
}
peek
public T peek() throws EmptyCollectionException
{
if (isEmpty())
throw new EmptyCollectionException("stack");
return stack[top-1];
}
isEmpty
```
public boolean isEmpty()
{
if(size()==0) {
return true;
}else {
return false;
}
}
```
size
public int size()
{
return top;
}
toString
public String toString()
{
String string="";
for(int i=0;i<top;i++) {
System.out.println(stack[i]);
}
return string;
}
第四章 链式结构-栈
- 链式结构是一种数据结构,它使用对象引用变量来创建对象之间的链接。
- 对象引用变量存放的是对象的地址,表示该对象在内存中的存储位置。
- 通常并不显示地址,而是将引用变量描绘成一种“指向”对象的名字,称为“指针”。
- 在链表中存储的对象通常泛称为该链表的结点。
- 链表会按需动态增长,因此在本质上,他没有容量限制。
管理链表
- 访问链表唯一方式就是从第一个元素开始顺着链表往下进行,因为一旦first指针移到了指向链表的第二个元素,就再也没有指向第一个元素的指针了。
- 改变引用顺序是维护链表的关键。
- 插入结点:新添加结点的next引用被设置为指向链表的当前首结点,接着,指向链表前端的引用重新设置为指向这个新添加的结点。
- 删除结点:重置指向链表前端的引用,使其指向链表当前的次结点。
- 哨兵结点或哑结点可以作为一个假的第一结点,并没有真正表示列表中的某个元素。
- 递归:间接或直接调用自身的过程或方法。
- 程序栈/运行时栈:每调用一个方法,就会创建一个表示该调用的调用记录,并压入到程序栈中,因此,栈中的元素表示的是一个正在运行的程序中,到达某个位置时所调用的方法系列。
用链表实现栈
- 栈的链表实现是从链表的一端添加和删除元素。
- push操作:
- 创建一个新结点,该结点含有一个引用,指向要放置到栈中的对象
*把新结点的next引用设置为指向当前栈顶(如果栈为空,它就是null) - 把top引用设置为指向该新结点
- 递增栈的元素计数
- 创建一个新结点,该结点含有一个引用,指向要放置到栈中的对象
- pop操作
- 确保栈不为空
- 设置一个临时引用等于栈顶元素
- 设置top引用等于栈顶结点的next引用
- 递减栈的元素计数
- push和pop的复杂度都为O(1)
教材学习中的问题和解决过程
- 问题一:使用栈来穿越迷宫的原理
- 问题二:参考:java 用栈的原理(穷举)实现迷宫游戏
在一个封闭的空间内,用’0’表示可走,’1’表示墙;有一个起点和一个终点,需要找到从起点到终点的通路,还要保证在寻路的过程中不会出现来回走的情况。从起点出发,我们用0,1,2,3来表示上下左右,也就是寻路的方向;每走一步之后都按照0,1,2,3的方向进行试探可否走,如果能走,把能走的坐标和来时的方向进行压栈,栈里都是走过的路线,如果0不通走1,1不通走2,2不通走3,都不通退一格,继续按照0-->1-->2-->3的方向寻路。这就很符合栈的先进后出原理,坐标点在栈里的存储可以用数组实现,也可以用链表实现,这里使用链表。存放坐标和方向使用类的数组,好像叫什么结构体,习惯性叫类的数组。
-
问题二:关于泛型的理解
-
问题二解决:
泛型就是变量类型的参数化。在使用泛型前,存入集合中的元素可以是任何类型的,当从集合中取出时,所有的元素都是Object类型,需要进行向下的强制类型转换,转换到特定的类型。而强制类型转换容易引起运行时错误。泛型类型参数只能被类或接口类型赋值,不能被原生数据类型赋值,原生数据类型需要使用对应的包装类。
例如:
class GenericsTest<T>
声明了一个泛型类,这个T没有任何限制,实际上相当于Object类型,实际上相当于
class GenericsTest<T extends Object>
。
与Object泛型类相比,使用泛型所定义的类在声明和构造实例的时候,可以使用“<实际类型>”来一并指定泛型类型持有者的真实类型。类如
GenericsTest<Double> douTest=new
GenericsTest<Double>(new Double("33"));
当然,也可以在构造对象的时候不使用尖括号指定泛型类型的真实类型,但是你在使用该对象的时候,就需要强制转换了。比如:
GenericsTest douTest=new GenericsTest(new Double("33"));
实际上,当构造对象时不指定类型信息的时候,默认会使用Object类型,这也是要强制转换的原因。
代码调试中的问题和解决过程
-
问题一:在蓝墨云作业链表练习时,需要从键盘输入整数建立链表,我仿照课堂上老师演示的student事例,但是那个例子需要实例化Student对象,而作业要求是键盘输入不可提前预知数字的,所以无法继续实现。
-
问题一解决:我之前是想用栈来保存并循环输出,在王文彬同学的帮助下,实例化时改为如下
Node Head = new Node(Integer.parseInt(a[0]));
然后用循环插入创建链表
for (int i = 0; i < a.length-1; i++) {
Node x = new Node(Integer.parseInt(a[i+1]));
InsertNode(Head,x);
}
就可以实现了。
- 问题二:蓝墨云作业实现插入时,总是在最后插入数字
//插入
System.out.println();
System.out.println("请输入要插入的数字:");
Scanner scan3 = new Scanner(System.in);
int s = scan3.nextInt();
Node san = new Node(s);
System.out.println("请输入要插入的位置:");
Scanner scan4 = new Scanner(System.in);
int f = scan4.nextInt();
Node temp3=Head;
for (int i = 1;i<f;i++){
temp3=temp3.next;
}
InsertNode(Head,san);
System.out.println("插入后的链表为:");
PrintLinkedList(Head.next);
- 问题二解决:我错误的地方在于我插入时使用的循环是往中间插的,而我使用的插入方法InsertNode是尾插法,所以要考虑到插入有三种情况,头插中间插和尾插,要分别来写插入。修改后的代码如下。
//插入
System.out.println();
System.out.println("请问想要插入什么数字:");
Scanner y = new Scanner(System.in);
int pos2=y.nextInt();
Node insertnumber = new Node(pos2);
System.out.println("请问想要插入在什么位置:");
Scanner qq = new Scanner(System.in);
int pos = qq.nextInt();
Node abc = Head;
if (pos==1){
System.out.println();
System.out.println("插入后的链表为:");
Firstinsert(Head,insertnumber);
PrintLinkedList(Head);
Node ii=new Node(pos2);
InsertNode(Head,ii);
int num2=Head.data;
Node numm=new Node(num2);
InsertNode(Head,numm);
Node temp0=Head;
}
else if (pos!=1&&temp.next!=null){
for (int i = 1;i<pos-1;i++){
linshi = linshi.next;
}
insert(Head,abc,abc.next,insertnumber);
System.out.println("插入后的链表为:");
PrintLinkedList(Head);
InsertNode(Head,xxx);
}
else if (temp.next==null)
{
InsertNode(Head,insertnumber);
System.out.println("插入后的链表为:");
PrintLinkedList(Head);
InsertNode(Head,xxx);
}
代码托管
现在是4975行,上学期结束时3872行,增加了1163行。
-
PP3.2
-
PP3.8
-
PP3.9
-
PP4.2
由于安卓无法git,代码如下
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.util.Stack;
public class MainActivity777 extends AppCompatActivity {
LinkedStack<String> stack = new LinkedStack();
String xxx = "";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main777);
Button button1 = (Button) findViewById(R.id.button);
Button button2 = (Button) findViewById(R.id.button2);
button1.setOnClickListener(new myButtonListener());
button2.setOnClickListener(new myButtonListener1());
}
public class myButtonListener implements View.OnClickListener {
@Override
public void onClick(View v) {
EditText editText1 = (EditText) findViewById(R.id.editText);
stack.push(editText1.getText().toString());
TextView editText2 = (TextView) findViewById(R.id.editText4);
editText2.setText(editText1.getText(), TextView.BufferType.EDITABLE);
xxx += "进入栈中的数是:"+ stack.peek()+"\n";
editText2.setText(xxx ,TextView.BufferType.EDITABLE);
xxx += "当前栈是:" +stack+"\n";
editText2.setText(xxx , TextView.BufferType.EDITABLE);
}
}
public class myButtonListener1 implements View.OnClickListener{
@Override
public void onClick(View v){
EditText editText1 = (EditText) findViewById(R.id.editText);
stack.pop();
TextView editText2=(TextView) findViewById(R.id.editText4);
editText2.setText(editText1.getText(),TextView.BufferType.EDITABLE);
xxx += "从栈中弹出的数是:" +stack.peek()+"\n";
editText2.setText( xxx, TextView.BufferType.EDITABLE);
xxx += "当前栈是:" +stack+"\n";
editText2.setText(xxx, TextView.BufferType.EDITABLE);
}
}
}
上周考试错题总结
-
错题一:
-
错题一解析:应该是健壮性的特征是出错情况下可以得到恰当处理的程度。
-
错题二:
-
错题二解析:应该是题目错了。nlogn的阶次大于2n。
结对及互评
点评模板:
-
博客中值得学习的或问题:
- 20172305谭鑫的博客中课本疑难问题解决的很好,内容全面,教材中遇到的问题和代码中的问题过程记录的十分详细。
- 20172323王禹涵的博客中课本内容总结详实,感悟深刻,但遇到的问题解决过程可以更加详细一点。
-
基于评分标准,我给谭鑫的博客打分:11分。得分情况如下:
- 问题加分8分
- 感悟不假大空加1分
- 排版精美的加1分
-正确使用Markdown语法加1分
-模板中的要素齐全加1分
- 基于评分标准,我给王禹涵的博客打分:7分。得分情况如下:
- 排版精美的加1分
- 问题加分3分
- 感悟不假大空加1分
-正确使用Markdown语法加1分
-模板中的要素齐全加1分
其他
对LinkedStack类不是很熟悉,还有链表里的头插法,但同时对链表还有栈的学习更加深入了一些。
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | |
---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 |
第一周 | 0/0 | 1/1 | 8/8 |
第二周 | 1163/1163 | 1/2 | 15/23 |