20172313 2018-2019-1 《程序设计与数据结构》实验一报告
课程:《程序设计与数据结构》
班级: 1723
姓名: 余坤澎
学号:20172313
实验教师:王志强
实验日期:2018年9月26日
必修/选修: 必修
1.实验内容
- 实验一
链表练习,要求实现下列功能:
通过键盘输入一些整数,建立一个链表;
这些数是你学号中依次取出的两位数。 再加上今天的时间。
例如你的学号是 20172301
今天时间是 2018/10/1, 16:23:49秒数字就是20, 17,23,1, 20, 18,10,1,16,23,49
打印所有链表元素, 并输出元素的总数。 在你的程序中,请用一个特殊变量名来纪录元素的总数,变量名就是你的名字。 例如你叫 张三, 那么这个变量名就是
int nZhangSan = 0; //初始化为 0.
做完这一步,把你的程序签入源代码控制(git push)。 - 实验二
实现节点插入、删除、输出操作;
继续你上一个程序,扩展它的功能,每做完一个新功能,或者写了超过10行新代码,就签入代码,提交到源代码服务器;
从磁盘读取一个文件, 这个文件有两个数字。
从文件中读入数字1, 插入到链表第 5 位,并打印所有数字,和元素的总数。 保留这个链表,继续下面的操作。
从文件中读入数字2, 插入到链表第 0 位,并打印所有数字,和元素的总数。 保留这个链表,并继续下面的操作。
从链表中删除刚才的数字1. 并打印所有数字和元素的总数。
签入所有代码。 - 实验三
使用冒泡排序法或者选择排序法根据数值大小对链表进行排序;
如果你学号是单数, 选择冒泡排序,否则选择选择排序。
在排序的每一个轮次中,打印元素的总数,和目前链表的所有元素。 在实验二得到的程序中继续扩展, 用同一个程序文件,写不同的函数来实现这个功能。 仍然用 nZhangSan (你的名字)来表示元素的总数。 - 实验四
用数组代替链表实现实验一和实验二。 - 实验五
用数组代替链表实现实验三
2. 实验过程及结果
实验一
- 学习教材,了解链表的数据结构并结合网络上的相关知识进行实现。
- 使用StringTokenizer分割输入的数据,将其存入到链表中。
LinkedQueue lq = new LinkedQueue();
System.out.println("请输入一系列整数:");
Scanner scan = new Scanner(System.in);
String str = scan.nextLine();
StringTokenizer st = new StringTokenizer(str);
while(st.hasMoreTokens()){
lq.enqueue(st.nextToken());
}
实验二
- 实验二要求实现节点的插入,删除和输出。注意在节点添加和删除时指针的先后指向顺序,防止链表丢失。操作完成后要对表示链表元素数目的变量(nYuKunpeng)进行自增和自减。
insert 方法 (将数据(element)插入适当的索引(A)处)
public void insert(T element1, int A){
LinearNode<T> node1 = new LinearNode<T>(element1);
LinearNode<T> current = head;
if(A==0){
node1.setNext(current);
head = node1;
}
else{
for(int i = 1; i < A; i ++)
current = current.getNext();
node1.setNext(current.getNext());
current.setNext(node1);
}
nYuKunpeng++;
}
delete 方法 (删除指定索引处(A)的元素)
public void delete(int A){
LinearNode current, temp = null;
current = head;
if( A == 0)
head = head.getNext();
else{
for(int i = 0; i < A; i ++) {
temp = current;
current = current.getNext();
}
temp.setNext(current.getNext());
}
nYuKunpeng --;
}
ToString 方法(便历链表依次打印)
public String toString(){
String result = "";
LinearNode<T> current = head;
int a = nYuKunpeng;
while(a > 0) {
result += current.getElement()+ ",";
current = current.getNext();
a--;
}
return result;
}
实验三
- 在实验二的基础上对元素进行排序,由于我使用的是冒泡排序法,在每次的循环中把该位置的元素与该元素之前位置的元素相比较,在合适的情况下两个节点内保存的数据进行交换,已达到冒泡的目的。
sort 方法
public void sort(){
LinearNode2<T> current, temp = null;
T n;
for(current = head; current != null; current = current.getNext()){ //外层循环遍历链表内的元素
for(temp = current;temp.getPrevious() != null; temp = temp.getPrevious()){ //内层循环使用该元素与他之前的元素进行比较
if(Integer.parseInt(temp.getPrevious().getElement()+"")>Integer.parseInt(temp.getElement()+ "")){
n = temp.getPrevious().getElement(); //使用临时变量n来交换两个节点内的元素
temp.getPrevious().setElement(temp.getElement());
temp.setElement(n);
}
}
System.out.println("此轮排序后元素的顺序" + toString() + "此时元素的个数为" + size());
}
}
实验四
- 实验四与实验一二的不同之处在于这里采用数组进行实现。链表是动态的,在进行插入和删除操作时直接可以在原链表上进行操作,不占用多余的储存空间。但如果是数组的话,需要考虑数组的长度。在插入和删除时,如果直接对原数组操作时会比较麻烦容易出错,所以我在这里的思路是另外申请一个数组,先把原数组要删除或插入地方的索引前面的元素遍历进入新的数组中,再对需要添加或删除的元素进行操作,之后再遍历该索引后的元素。
add方法 (把指定的元素(element)插入到适当的索引处(a))
//add方法分为两种,在不加索引参数的时候直接在数组的末尾进行添加,在这里只列举有索引参数的方法,下面的delete方法也是如此。
public void add(T element, int a){
T[] B = (T[])(new Object[size() + 1]);
for(int i =0; i < a;i ++)
B[i] = A[i];
B[a] = element;
for(int i = a + 1;i < size() + 1; i ++ ) {
B[i] = A[i - 1];
}
A = B;
nYuKunpeng ++;
}
delete方法 (删除指定索引处(a)的元素)
public void delete(int a){
T[] B = (T[])(new Object[size() - 1 ]);
for(int i = 0;i < a; i++)
B[i] = A[i];
for(int i = a;i < size() - 1; i++)
B[i] = A[i+1];
A = B;
nYuKunpeng--;
}
实验五
- 数组的排序实现较为简单,在这里直接吧重要代码贴上。
public void sort(){
for(int i=0;i<size();i++) {
for (int j = i; j > 0; j--) {
if (Integer.parseInt(A[j-1] + "") > Integer.parseInt(A[j]+ "")) {
T temp = A[j];
A[j] = A[j - 1];
A[j - 1] = temp;
}
}
System.out.println("此时元素为:" + toString()+ "元素的个数为" + size());
}
}
3. 实验过程中遇到的问题和解决过程
-
问题一:在做实验三的时候,发现在进行冒泡排序的时候,两个数无法进行比较,会显示数据被封装。
-
问题一解决方案:强制类型转换在T类型和char类型当中进行转换是不适用的,先把T类型转化为String类型,在转换为int就可以了。
-
问题二:在做实验四的时候,在进行元素的插入后发现元素会减少一个。
-
问题二解决方案:在插入元素的时候,记录数组内元素个数的变量nYuKunpeng没有进行自增,导致最后在ToString时遍历数组会导致元素个数少一。
-
问题三:我在进行链表冒泡排序的时候,不是很能理解冒泡排序的含义。
算法原理
冒泡排序算法的原理如下:
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
算法稳定性:
冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以,如果两个元素相等,是不会再交换的;如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。
- 问题三解决方案:我在进行排序的时候一直想着把最小的数值放在前面,为了能够得到所选节点前面的节点,所以我只好使用双向链表,但这样势必会增加代码的繁琐量。我在上网查询了资料后,发现了一种更好的排序代码,在这里贴上,代码博客地址附在本博客末尾。
//单链表冒泡排序
public Node blueSortList(Node node){
System.out.println("blue start...");
//当前节点
Node cur = node.next;
//下一个节点
Node next = cur.next;
//前一个节点,两节点n1,n2交换位置时需要前一个节点的next指向n2节点
Node upperNode = node;
//一次排序的最后一个节点
Node lastNode = null;
int i = 1;
//当第二个节点为当次排序的最后一个节点时,整体排序结束
while(node.next != lastNode){
//当下一个节点为一次次排序的最后一个节点时,本次排序结束。
if(next == lastNode){
lastNode = cur;
cur = node.next;
next = cur.next;
upperNode = node;
}else if(next.value < cur.value){
cur.next = next.next;
next.next = cur;
upperNode.next = next;
upperNode = next;
}else{
upperNode = cur;
cur = cur.next;
}
next = cur.next;
System.out.println("第" + i++ + "次排列结果:");
printList(node.next);
}
System.out.println("blue end...");
return node;
}
其他
这次实验的难度相对来说不是特别高,一方面没有新的知识,另一方面其中需要的很多代码在之前也有练习过。尽管如此,由于自己的粗心和理解的不透彻,还是在实验中浪费了不少时间,希望能够在以后的学习生活中继续努力,不断进步!