数据结构题目训练记录(Java书写) One
此篇笔记,涉及到 数据结构中 序列,链表的使用
一、最大子列和问题
给定K个整数组成的序列{ N1, N2, ..., NK },“连续子列”被定义为{ Ni, Ni+1, ..., Nj },其中 1。“最大子列和”则被定义为所有连续子列元素的和中最大者。例如给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4, 13 }有最大的和20。现要求你编写程序,计算给定整数序列的最大子列和。
本题旨在测试各种不同的算法在各种数据情况下的表现。各组测试数据特点如下:
- 数据1:与样例等价,测试基本正确性;
- 数据2:102个随机整数;
- 数据3:103个随机整数;
- 数据4:104个随机整数;
- 数据5:105个随机整数;
输入格式:
输入第1行给出正整数K (≤);第2行给出K个整数,其间以空格分隔。
输出格式:
在一行中输出最大子列和。如果序列中所有整数皆为负数,则输出0。
输入样例:
6
-2 11 -4 13 -5 -2
输出样例:
20
第一种方法:三重循环法,时间复杂度为 O(n3)
1 /** 2 * 这里用的第一种方法是三重循环方法 时间复杂度为 O(n^3) 3 * 法一:三重循环。第一重标记子列最左端,第二重标记子列最右端,第三重由子列左端累加到子列右端。 4 */ 5 public class MaxSum1{ 6 public static int MaxSum1s(int A[]) 7 { 8 int ThisSum = 0, MaxSum = 0; 9 int i, j ,k; 10 for(i = 0; i < A.length; i++) // i 是子列最左端 11 { 12 for(j = i; j < A.length; j++) 13 { 14 ThisSum = 0; // 每次都要将 ThisSum 归零,累加新一轮的子列和 15 for (k = i; k < j; k++) // 将 A[i] 到 A[j] 累加,得到子列和 16 ThisSum += A[k]; 17 if(ThisSum > MaxSum) // 如果这一轮的子列和比最大子列和还大,存入 MaxSum 18 MaxSum = ThisSum; 19 } 20 } 21 return MaxSum; 22 } 23 24 public static void main(String[] args) 25 { 26 int lists[] = new int[] {-2 ,11, -4, 13, -5, -2}; 27 System.out.println(MaxSum1s(lists)); 28 } 29 }
第二种方法:二重循环法
1 /** 2 * 法二:二重循环。对于相同的子列左端位置 i ,不同的右端位置 j ,我们只要每次在右端累加一项,即可求得每一个子列和。 3 */ 4 public class MaxSum2{ 5 public static int MaxSums(int [] A) 6 { 7 int MaxSum = 0, ThisSum = 0; 8 int i, j; 9 for(i = 0; i < A.length; i++) 10 { 11 ThisSum = 0; 12 for(j = i; j < A.length; j++) 13 { 14 ThisSum += A[j]; 15 if (ThisSum > MaxSum) // 这里改成了,从 i 到 任意一处 j 来进行比较 16 { 17 MaxSum = ThisSum; 18 } 19 } 20 } 21 return MaxSum; 22 } 23 24 public static void main(String [] args) 25 { 26 int lists[] = new int[] {-2 ,11, -4, 13, -5, -2}; 27 System.out.println(MaxSums(lists)); 28 } 29 }
第三种方法:分而治之
1 /** 2 * @author 小喵钓鱼 3 * @date 2020-02-02 13:53 4 * @veision 1.10 5 * 方法三:分而治之。 6 * 将序列从中分为左右两个子序列。 7 * 递归求得两个子列的最大和。 8 * 从中分点分头向左、右两边扫描,找出跨过分界线的最大子列和。 9 * 输出这三个子列和最大的一个。 10 */ 11 public class MaxSum3 { 12 // 比较三个数的 13 public static int Max3(int A, int B, int C) 14 { 15 return (A>B)?(A>C?A:C):(B>C?B:C); 16 } 17 18 /** 19 * 分治 list[left] 和 list[right] 的最大子列和 20 * @param List 21 * @param left 22 * @param right 23 * @return 24 */ 25 public static int DivideAndConquer(int List[], int left, int right) 26 { 27 int MaxLeftSum, MaxRightSum; //存放左右子问题的解。 28 int MaxLeftBorderSum, MaxRightBorderSum; //存放跨分界线的结果。 29 30 int LeftBorderSum, RightBorderSum; 31 int center, i; 32 33 /*递归的终止条件,子列只有1个数字*/ 34 if ( left == right ) { 35 if ( List[left] > 0 ) return List[left]; 36 else return 0; 37 } 38 39 /* “分”的过程 */ 40 center = ( left + right ) / 2; //找到中分点。 41 MaxLeftSum = DivideAndConquer ( List, left, center ); //递归求左子列和。 42 MaxRightSum = DivideAndConquer ( List, center+1, right ); //递归求右子列和。 43 44 /*求跨分界线的最大子列和*/ 45 MaxLeftBorderSum = 0; LeftBorderSum = 0; 46 for ( i = center; i >= left; i-- ) { 47 LeftBorderSum += List[i]; 48 if ( LeftBorderSum > MaxLeftBorderSum ) 49 MaxLeftBorderSum = LeftBorderSum; 50 }//左边扫描结束。 51 52 MaxRightBorderSum = 0; RightBorderSum = 0; 53 for ( i = center+1; i <= right; i++ ) { 54 RightBorderSum += List[i]; 55 if ( RightBorderSum > MaxRightBorderSum ) 56 MaxRightBorderSum = RightBorderSum; 57 }//右边扫描结束。 58 59 /*返回“治”的结果*/ 60 return Max3(MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum ); 61 } 62 63 /*此函数用于保持接口相同*/ 64 public static int MaxSum3 ( int List[], int N ) { 65 return DivideAndConquer(List, 0, N - 1); 66 } 67 68 public static void main(String[] args) { 69 int lists[] = new int[] {-2 ,11, -4, 13, -5, -2}; 70 System.out.println(MaxSum3(lists, lists.length)); 71 } 72 }
二、Maximum Subsequence Sum (最大序列和,此题和上题比较类似)
Given a sequence of K integers { N1, N2, ..., NK }. A continuous subsequence is defined to be { Ni, Ni+1, ..., Nj } where 1. The Maximum Subsequence is the continuous subsequence which has the largest sum of its elements. For example, given sequence { -2, 11, -4, 13, -5, -2 }, its maximum subsequence is { 11, -4, 13 } with the largest sum being 20.
Now you are supposed to find the largest sum, together with the first and the last numbers of the maximum subsequence.
Input Specification:
Each input file contains one test case. Each case occupies two lines. The first line contains a positive integer K (≤). The second line contains K numbers, separated by a space.
Output Specification:
For each test case, output in one line the largest sum, together with the first and the last numbers of the maximum subsequence. The numbers must be separated by one space, but there must be no extra space at the end of a line. In case that the maximum subsequence is not unique, output the one with the smallest indices i and j (as shown by the sample case). If all the K numbers are negative, then its maximum sum is defined to be 0, and you are supposed to output the first and the last numbers of the whole sequence.
Sample Input:
10
-10 1 2 3 4 -5 -23 3 7 -21
Sample Output:
10 1 4
1 /** 2 * @author 小喵钓鱼 3 * @date 2020-02-02 14:28 4 * @veision 1.10 5 */ 6 public class Maximum { 7 public static void Maximums(int list[], int N) 8 { 9 int ThisSum, MaxSum, Forntdata, Enddata; 10 int sublen; // 设置 子列差 11 sublen = Forntdata = Enddata = ThisSum = 0; 12 MaxSum = -1; 13 for (int i = 0; i < N; i++) 14 { 15 ThisSum += list[i]; 16 sublen ++; // 差 + 1 17 if (ThisSum > MaxSum) // 如果子列和大于最大子列和 18 { 19 MaxSum = ThisSum; // 最大和 20 Enddata = list[i]; // 结尾子序列数据 21 Forntdata = list[i - sublen + 1]; // 开始子序列数据 22 } 23 if (ThisSum < 0) // 如果子列和 < 0 24 { 25 ThisSum = 0; 26 sublen = 0; 27 } 28 } 29 30 if (MaxSum < 0) 31 { 32 System.out.println(0 + " " + list[0] + " " + list[N - 1]); 33 } 34 else 35 { 36 System.out.println(MaxSum + " " + Forntdata + " " + Enddata); 37 } 38 } 39 40 public static void main(String[] args) { 41 int list [] = new int[]{-10, 1, 2, 3, 4, -5, -23, 3, 7, -21}; 42 int N = list.length; 43 Maximums(list, N); 44 } 45 }
三、二分查找
顾名思义,就是从中间比较,不断分,来进行查找的一种方法,但是缺点是查找的子序列必须是已经排好序了的
1 /** 2 * @author 小喵钓鱼 3 * @date 2020-02-02 14:38 4 * @veision 1.10 5 */ 6 public class binary_search { 7 public static int binary_search_pp(int list[], int searchKey) 8 { 9 int Center; // 中间坐标 10 int lower = 0; 11 int upper = list.length - 1; 12 while (true) 13 { 14 Center = (lower + upper) / 2; // 更新 15 if (list[Center] == searchKey){ // 如果第一次就找到,直接返回 16 return Center; 17 } 18 19 else if(lower > upper) // 如果最低坐标,比最高坐标大,那么代表这个数组就一个元素 20 { 21 return list.length; 22 } 23 else { 24 if (list[Center] < searchKey) // 如果 < 25 lower = Center + 1; 26 else // 如果 大 27 upper = Center - 1; 28 } 29 } 30 } 31 32 public static void main(String[] args) { 33 int key [] = new int[]{1, 2, 3, 4 ,5 ,6}; 34 System.out.println(binary_search_pp(key, 3)); 35 } 36 }
四、两个有序链表序列的合并
怎么说呢,感觉自己写的有点小问题,不过无伤大雅,虽然是倒叙就是了,不过思路还是可以借鉴的
虽然是用 Java写的,但是并没有用到 相应的库,自行写的 单向链表类。
1 /** 2 * @author 小喵钓鱼 3 * @date 2020-02-02 14:59 4 * @veision 1.10 5 * L1和L2是给定的带头结点的单链表,其结点存储的数据是递增有序的;函数Merge要将L1和L2合并为一个非递减的整数序列。应直接使用原序列中的结点,返回归并后的带头结点的链表头指针。 6 */ 7 public class Link{ 8 public int iData; // data item 9 public double dData; // data item 10 public Link next; // next link in list 11 public Link(int id, double dd) 12 { 13 iData = id; // initializa data 14 dData = dd; 15 } 16 public void displayLink() 17 { 18 System.out.println("{" + iData + ", " + dData + "}"); 19 } 20 } 21 22 23 class LinkList { 24 private Link first; // ref to first link on list 25 26 public void LinkList() { 27 first = null; 28 } 29 30 public boolean isEmpty() { 31 return (first == null); 32 } 33 34 public void insertFirst(int id, double dd) { 35 Link newLink = new Link(id, dd); 36 newLink.next = first; // newLink --> old first 37 first = newLink; // first --> newLink 38 } 39 40 public Link deleteFirst() { 41 Link temp = first; 42 first = first.next; 43 return temp; 44 } 45 46 public void displayList() { 47 System.out.println("List(first --> last)"); 48 Link current = first; // start at beginning of list 49 while (current != null) { 50 current.displayLink(); // print data 51 current = current.next; // move to next link 52 } 53 System.out.println(" "); 54 } 55 56 public Link find(int Key) { 57 Link current = first; 58 while (current.dData != Key) { 59 if (current.next == null) 60 return null; // didn't find it 61 else 62 current = current.next; 63 } 64 return current; 65 } 66 67 public void Merge(LinkList L1) 68 { 69 LinkList L = new LinkList(); 70 Link pa, pb, pc; 71 pa = first; 72 pb = L1.first; 73 pc = L.first; 74 int count = 0; 75 while (pa != null && pb != null) 76 { 77 System.out.println(pa.dData + "=" + pb.dData); 78 if (pa.dData >= pb.dData) 79 { 80 if (count < 1) 81 { 82 L.first = pa; 83 count ++; 84 } 85 else { 86 pc.next = pa; 87 } 88 pc = pa; 89 pa = pa.next; 90 } 91 else { 92 if (count < 1) 93 { 94 L.first = pb; 95 count++; 96 // pc .next = pb; 97 } 98 else { 99 pc.next = pb; 100 } 101 pc = pb; 102 pb = pb.next; 103 } 104 } 105 106 pc.next = pa != null? pa: pb; 107 L1.first = null; 108 this.first = L.first; 109 } 110 } 111 112 class LinkListApp{ 113 public static void main(String [] args) 114 { 115 LinkList theList = new LinkList(); // make new list 116 117 theList.insertFirst(1, 2.29); // insert four items 118 theList.insertFirst(4, 4.29); 119 theList.insertFirst(6, 6.99); 120 theList.insertFirst(7, 8.99); 121 122 123 LinkList nextList = new LinkList(); 124 nextList.insertFirst(2, 2.30); 125 nextList.insertFirst(3, 3.40); 126 nextList.insertFirst(5, 5.33); 127 128 129 theList.Merge(nextList); 130 theList.displayList(); 131 } 132 }
五、一元多项式的乘法与加法运算
设计函数分别求两个一元多项式的乘积与和。
输入格式:
输入分2行,每行分别先给出多项式非零项的个数,再以指数递降方式输入一个多项式非零项系数和指数(绝对值均为不超过1000的整数)。数字间以空格分隔。
输出格式:
输出分2行,分别以指数递降方式输出乘积多项式以及和多项式非零项的系数和指数。数字间以空格分隔,但结尾不能有多余空格。零多项式应输出0 0
。
输入样例:
4 3 4 -5 2 6 1 -2 0
3 5 20 -7 4 3 1
输出样例:
15 24 -25 22 30 21 -10 20 -21 8 35 6 -33 5 14 4 -15 3 18 2 -6 1
5 20 -4 4 -5 2 9 1 -2 0
代码示例
1 /** 2 * @author 小喵钓鱼 3 * @date 2020-02-02 18:18 4 * @veision 1.10 5 * 设计函数分别求两个一元多项式的乘积与和。 6 * 7 * 输入格式: 8 * 输入分2行,每行分别先给出多项式非零项的个数,再以指数递降方式输入一个多项式非零项系数和指数(绝对值均为不超过1000的整数)。数字间以空格分隔。 9 * 10 * 输出格式: 11 * 输出分2行,分别以指数递降方式输出乘积多项式以及和多项式非零项的系数和指数。数字间以空格分隔,但结尾不能有多余空格。零多项式应输出0 0。 12 */ 13 class Links 14 { 15 public int iData; 16 public int dData; 17 public Links next; // next Link 18 public Links(int id, int dd) 19 { 20 iData = id; 21 dData = dd; 22 } 23 24 public void displayLink() 25 { 26 System.out.println("{" + iData + ":" + dData + "}"); 27 } 28 29 public void setId(int id) 30 { 31 this.iData = id; 32 } 33 } 34 class LinkList{ 35 public Links first; // ref to the first link 36 public Links last; // ref to the last link 37 38 public void LinkList() 39 { 40 first = null; 41 last = null; 42 } 43 44 public boolean isEmpty() 45 { 46 return (first == null); 47 } 48 49 public void insertFirst(int id, int dd) 50 { 51 Links newLink = new Links(id, dd); 52 if (isEmpty()) 53 { 54 last = newLink; // newLink <-- last 55 } 56 newLink.next = first; // newLink --> old first 57 first = newLink; 58 } 59 60 public void insertAfter(int id, int dd) 61 { 62 Links newLink = new Links(id, dd); 63 if (isEmpty()) 64 { 65 first = newLink; // first --> newLink 66 } 67 else 68 last.next = newLink; // old last --> newLink 69 last = newLink; // newLink <-- last 70 } 71 72 public void displayLink() 73 { 74 System.out.println("List(first --> last)"); 75 Links current = first; // start at beginning of list 76 while (current != null) { 77 current.displayLink(); // print data 78 current = current.next; // move to next link 79 } 80 System.out.println(" "); 81 } 82 83 } 84 public class Mult_Add { 85 public static void ReadOnly(LinkList P1) 86 { 87 Scanner scanner = new Scanner(System.in); 88 int N = scanner.nextInt(); // 位数 89 for (int i = 0; i < N; i++) 90 { 91 int idata = scanner.nextInt(); 92 int ddata = scanner.nextInt(); 93 P1.insertAfter(idata, ddata); 94 } 95 } 96 97 public static LinkList Add(LinkList T1, LinkList T2) 98 { 99 LinkList P = new LinkList(); 100 101 if (T1 == null || T2 == null) 102 { 103 return null; 104 } 105 // 分别指向 T1, T2 的第一个元素 106 Links link1 = T1.first; 107 Links link2 = T2.first; 108 109 while (link1 != null && link2 != null) { // 两者均不为空时 110 if (link1.dData > link2.dData) { 111 P.insertAfter(link1.iData, link1.dData); 112 link1 = link1.next; 113 } 114 else if(link1.dData<link2.dData) 115 { 116 P.insertAfter(link2.iData, link2.dData); 117 link2 = link2.next; 118 } 119 else { // 两者指数相等时 120 if (link1.iData + link2.iData != 0) { 121 P.insertAfter(link1.iData + link2.iData, link1.dData); 122 } 123 link1 = link1.next; 124 link2 = link2.next; 125 } 126 } 127 128 while (link1 != null) 129 { 130 P.insertAfter(link1.iData, link1.dData); 131 link1 = link1.next; 132 } 133 while (link2 != null) 134 { 135 P.insertAfter(link2.iData, link2.dData); 136 link2 = link2.next; 137 } 138 return P; 139 } 140 141 142 public static LinkList Mult(LinkList T1, LinkList T2) 143 { 144 LinkList P = new LinkList(); 145 // 分别指向第一个元素 146 Links link1 = T1.first; 147 Links link2 = T2.first; 148 149 /** 150 * 这里用的方法是先将两者每一个都像乘法那样相乘,然后进行同类项的合并 151 */ 152 while (link1 != null) 153 { 154 while (link2 != null) 155 { 156 int idata = link1.iData * link2.iData; 157 int ddata = link1.dData + link2.dData; 158 P.insertAfter(idata, ddata); 159 link2 = link2.next; 160 } 161 link1 = link1.next; 162 link2 = T2.first; 163 } 164 165 // 合并同类项 166 Links link3 = P.first; // 指向 P 的 第一个元素 167 Links tempPrevious = link3; // 同指 168 Links temp = link3.next; // 指向第二个元素 169 while (link3.next != null) // 当Link3 不等于 last 时。。。 170 { 171 while (temp != null) 172 { 173 if (temp.dData != link3.dData) // 如果 前一个和后一个的指数不同,则都向下进一个 174 { 175 temp = temp.next; 176 tempPrevious = tempPrevious.next; 177 } 178 else // 如果两者指数相同 179 { 180 link3.setId(link3.iData + temp.iData); // 更改前者系数 181 tempPrevious.next = temp.next; // 将 前者改成 temp 182 temp = temp.next; // temp = temp.next 183 } 184 } 185 link3 = link3.next; 186 tempPrevious = link3; 187 temp = link3.next; 188 } 189 return P; 190 } 191 192 public static void main(String[] args) { 193 LinkList p1 = new LinkList(); 194 ReadOnly(p1); 195 p1.displayLink(); 196 197 LinkList p2 = new LinkList(); 198 ReadOnly(p2); 199 p2.displayLink(); 200 LinkList P = Add(p1, p2); 201 P.displayLink(); 202 203 LinkList P3 = Mult(p1, p2); 204 P3.displayLink(); 205 } 206 }