一、概要
(一)线性结构
1、最常用,特点为数据元素间存在一对一的线性关系,一般有数组、队列、链表、栈。
2、分为两种存储结构:链式存储结构和顺序存储结构,前者存储地址不连续,后者连续。
(二)非线性结构
1、一般有二维数组、多维数组、广义表、树结构、图结构。
2、大多算法与树结构、图结构关联。
二、稀疏数组(sparsearray)
1
| 当一个数组中大部分为 0 或 同一个值 时,即去掉无意义的记录
|
1、处理方法:
记录数组有几行几列,和不同的值。
例:
[ 0 ] {总行数,总列数,有效值个数}
[ 1 ] {所在行,所在列,有效值}
…
**(1)二维数组转稀疏数组:**遍历总列数、总行数、有效值个数。根据sum创建稀疏数组,将二维有效数据存入稀疏数组。
(**2)稀疏数组转原始数组:**读取稀疏数组的第一行,根据第一行数据创建原始的二维数组,再读取后几行的数据赋值即可。
2、代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| public class sparsearray { public static void main(String[] args) { int[][] TowArr = new int[11][11]; TowArr[0][0] = 1; TowArr[1][1] = 2; TowArr[1][2] = 2; TowArr[10][10] = 1; for(int[] row : TowArr){ for(int data : row){ System.out.printf("%d\t",data); } System.out.println(); }
int sum = 0; for(int i = 0 ; i < TowArr.length;i++){ for(int j = 0;j < TowArr[i].length;j++){ if(TowArr[i][j] != 0){ sum++; } } }
int[][] sparseArr = new int[sum + 1][3]; sparseArr[0][0] = TowArr.length; sparseArr[0][1] = TowArr[0].length; sparseArr[0][2] = sum;
int count = 0; for(int i = 0 ; i < TowArr.length;i++){ for(int j = 0;j < TowArr[i].length;j++){ if(TowArr[i][j] != 0){ count++; sparseArr[count][0] = i; sparseArr[count][1] = j; sparseArr[count][2] = TowArr[i][j]; } } }
System.out.println(); System.out.println("==========稀疏数组============="); for(int[] row : sparseArr){ for(int data : row){ System.out.printf("%d\t",data); } System.out.println(); }
int[][] TOWArr2 =new int[sparseArr[0][0]][sparseArr[0][1]]; System.out.println("==========二维数组恢复=========="); for(int i = 1;i<sparseArr.length;i++){ TOWArr2[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2]; }
for(int[] row : TOWArr2){ for(int data : row){ System.out.printf("%d\t",data); } System.out.println(); } } }
|
三、队列(Queue)
1、处理方法:
建立环形数组(取模的方式实现)
定义front,rear分别代表队首第一个元素和队尾最后一个元素),初始值都为1
当队列满时(rear + 1)% maxSize == front
当队列空时,rear == front
队列中有效数据个数:(rear + maxSize - front) %maxSize
2、代码实现:用%建立环形队列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| class ArrayQueue{ private int maxSize,front,rear; private int[] QueArr;
public ArrayQueue(int arrMaxSize){ maxSize = arrMaxSize + 1; QueArr = new int[maxSize]; front = 0; rear = 0; }
public boolean isFull(){ return (rear + 1) % maxSize == front ; }
public boolean isEmpty(){ return rear == front; }
public void addQueue(int n){ if(isFull()){ System.out.println("队列已满"); return; } QueArr[rear] = n; rear = (rear + 1) % maxSize;
}
public int getQueue(){ if(isEmpty()){ throw new RuntimeException("队列空,不能取数据"); } int value = QueArr[front]; front = (front + 1) % maxSize; return value; }
public int size(){ return (rear + maxSize - front) % maxSize ; } public void showQueue(){ if(isEmpty()){ System.out.println("队列为空"); return; } for (int i = front; i < front + size();i++) { System.out.printf("QueArr[%d]=%d\n",i % maxSize,QueArr[i % maxSize]); } } public int headQueue(){ if(isEmpty()){ System.out.println("没有数据"); throw new RuntimeException("队列为空"); } return QueArr[front]; }
|
3、scanner、boolean的用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| Scanner scanner = new Scanner(System.in); char key = ' '; boolean loop = true; while (loop){ key = scanner.next().charAt(0); case 'a': System.out.println("输入一个数:"); int value = scanner.nextInt(); break; } case 'e': scanner.close(); loop = false; System.out.println("程序退出"); break; }
|
三、链表(Linked List)
(一)单链表(Single Linked List)
1 2 3
| 以结点的方式存储,每个节点包含data域、next域(指向下一个节点) 链表的各个节点不一定是连续存放的 链表分类:带节结点和无头节点的链表
|
1、处理方法:
设置头节点head
创建辅助节点temp
创造类属性中含他的对象next
使用temp遍历(temp=temp.next)使链表的元素.next(temp.next=添加元素名)指向下一个元素
2、代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
|
public class LInkedList { public static void main(String[] args) {
Student student1 = new Student(1, "彭磊一号", "男"); Student student2 = new Student(2, "彭磊二号", "女"); Student student3 = new Student(3, "彭磊三号", "人妖"); Student student4 = new Student(4, "彭磊四号", "不详");
SingleLinkedList singleLinkedList = new SingleLinkedList(); singleLinkedList.addByOrder(student1); singleLinkedList.addByOrder(student4); singleLinkedList.addByOrder(student3); singleLinkedList.addByOrder(student2);
singleLinkedList.ShowList();
Student newstudent = new Student(2, "彭磊的二号修改", "不男不女"); singleLinkedList.update(newstudent); System.out.println("=============="); singleLinkedList.ShowList();
System.out.println("=============="); singleLinkedList.del(3); singleLinkedList.ShowList();
System.out.println("链表长度为:" + singleLinkedList.getLength(singleLinkedList.getHead())); System.out.println("倒数第2个元素为" + singleLinkedList.FindLastIndexNode(singleLinkedList.getHead(), 1));
singleLinkedList.reverseList(singleLinkedList.getHead()); singleLinkedList.ShowList(); } }
class Student{
public int No; public String name; public String sex; public Student next;
public Student(int No,String name,String sex){ this.No =No; this.name = name; this.sex = sex; }
public String toString() { return "Student [no=" + No + ",name=" + name +",sex="+sex+"]"; } }
class SingleLinkedList{
private Student head = new Student(0,"","");
public Student getHead(){ return head; }
public void add(Student student){ Student temp = head; while(true){ if(temp.next==null){ break; } temp = temp.next; } temp.next = student; } public void addByOrder(Student student){ Student temp = head; boolean flag = false; while (true){ if(temp.next == null){ break; } if(temp.next.No>student.No){ break; }else if(temp.next.No == student.No){ flag = true; break; } temp = temp.next; } if(flag){ System.out.println("准备插入的学生id已经存在"); }else { student.next = temp.next; temp.next = student; } }
public void ShowList(){ if(head.next == null){ System.out.println("链表为空"); return; } Student temp = head.next; while (true){ if(temp == null){ break; } System.out.println(temp); temp = temp.next; } }
public void update(Student student){ if(head.next == null){ System.out.println("链表为空~"); return; } Student temp = head.next; boolean flag = false; while (true){ if(temp == null){ break; } if (temp.No == student.No){ flag = true; break; } temp = temp.next; } if(flag){ temp.name = student.name; temp.sex = student.sex; }else { System.out.println("没有找到该id"); } }
public void del(int No){
Student temp = head; boolean flag = false; while (true){ if(temp.next == null){ break; } if(temp.next.No == No){ flag = true; break; } temp = temp.next; } if(flag){ temp.next = temp.next.next; }else { System.out.printf("未找到该节点%d",No); } } public static int getLength(Student head){ if(head.next == null){ return 0; } int length = 0; Student cur = head.next; while (cur != null){ length++; cur = cur.next; } return length; }
public static Student FindLastIndexNode(Student head,int k){ if(head.next==null){ return null; } int length = getLength(head); if (k<=0 || k>=length){ return null; } Student cur = head.next; for (int i = 0; i < length-k; i++) { cur = cur.next; } return cur; } public static void reverseList(Student head){ if(head.next == null || head.next.next == null){ return; } Student cur = head.next; Student next = null; Student reverseHead = new Student(0,"",""); while (cur!=null){ next = cur.next; cur.next = reverseHead.next; reverseHead.next = cur; cur = next; } head.next = reverseHead.next; } }
|
(二)双链表(Double Linked List)
1
| 以结点的方式存储,每个节点包含data属性、next属性、pre属性
|
1、处理方法:
在单链表的基础上增加pre属性
修改方法与单链表相同
增加方法增加student.pre = temp;
删除方法改为
1 2
| temp.pre.next = temp.next; temp.next.pre = temp.pre;
|
2、代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
| public class DoubleLinkedListDemo { public static void main(String[] args) {
} }
class DStudent{ int no; String name; String sex; DStudent next; DStudent pre;
public DStudent(int no,String name,String sex){ this.no = no; this.name = name; this.sex = sex; }
public String toString(){ return "[no:"+no+",name:"+name+",sex:"+sex+"]" ; } }
class DoubleLinkedList{ DStudent head = new DStudent(0,"","");
public void add(DStudent student){ DStudent temp = head; while (true){ if(temp.next==null){ break; } temp = temp.next; } temp.next = student; student.pre = temp; }
public void updata(DStudent student){ DStudent temp = head; boolean flag = false; if(temp.next == null){ System.out.println("链表为空"); } while (true){ if(temp.next.no == student.no){ break; } if(temp.next == null){ flag = true; break; } temp = temp.next; } if(flag){ System.out.println("修改的数据不存在"); }else { temp.next.name = student.name; temp.next.sex = student.sex; } }
public void del(int no){ DStudent temp = head.next; boolean flag = false; if(temp.next == null){ System.out.println("链表为空"); } while (true){ if(temp.no == no){ if(temp.next==null){ flag = true; } break; } temp = temp.next; } if (flag){ temp.pre.next = null; }else { temp.pre.next = temp.next; temp.next.pre = temp.pre; } }
public void showList(){ DStudent temp = head; while (true){ if (temp.next == null){ break; }else { temp = temp.next; System.out.println(temp.toString()); } } }
public int getLength(){ DStudent temp = head; int length=0; while (true){ if (temp.next == null){ break; }else { length++; temp = temp.next; } } return length; } public void showIdEqual(int no){ DStudent temp = head; boolean flag = false; if(temp.next == null){ System.out.println("链表为空"); } while (true){ if(temp.next.no == no){ break; } if(temp.next == null){ flag = true; break; } temp = temp.next; } if(flag){ System.out.println("查看的数据的id不存在"); }else { System.out.println(temp.next); } } public static void reverseList(DStudent head){ if(head.next == null || head.next.next == null){ return; } DStudent cur = head.next; DStudent next = null; DStudent reverseHead = new DStudent(0,"",""); while (cur!=null){ next = cur.next; cur.next = reverseHead.next; reverseHead.next = cur; cur = next; } head.next = reverseHead.next; } }
|
(三)环形链表(Ring Linked List)
1
| 以结点的方式存储,每个节点包含data域、next域
|
1、处理方法:
构建:
创建第一个节点,让first节点指向该节点,并形成环形
之后当我们每创建一个新的节点,就把该节点加入到已有的环形链表中
遍历:
让辅助变量指向first节点,通过while循环遍历该环形链表即可
即 curboy.next == first时结束遍历
2、代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| public class RingLinkedListDemo { public static void main(String[] args) { RingLinkedList ringLinkedList = new RingLinkedList(); ringLinkedList.addBoys(5); ringLinkedList.showBoy(); } }
class Boy { private int no; private Boy next;
public Boy(int no) { this.no = no; }
public int getNo() { return no; }
public void setNo(int no) { this.no = no; }
public Boy getNext() { return next; }
public void setNext(Boy next) { this.next = next; }
} class RingLinkedList{ Boy first = null; public void addBoys(int nums) {
if (nums < 1) { System.out.println("nums 值不对!!"); return; } Boy curBoy = null;
for (int i = 1; i <= nums; i++) { Boy boy = new Boy(i);
if (i == 1) { first = boy; first.setNext(first); curBoy = first; } else { boy.setNext(first); curBoy.setNext(boy); curBoy = boy; } }
}
public void showBoy(){ if(first == null){ System.out.println("链表为空"); return; } Boy curBoy = first; while (true){ System.out.printf("小孩的编号%d\n",curBoy.getNo()); if (curBoy.getNext() == first){ break; } curBoy = curBoy.getNext(); } } }
|
四、栈(stack)
1 2 3
| 先入后出,栈顶(top)出栈(pop)、入栈(push) 出栈、入栈:出栈栈底不变,栈顶下移/上移 作用:处理递归调用、表达式转换、二叉树遍历、图形深度优先、子程序调用
|
1、处理方法:数组模拟栈
实现栈的思路分析
使用数组模拟栈,用定义top表示栈顶,初始化为-1
入栈:当有数据加入到栈时,top++;stack[top]=data
出栈:int values = stack[top];top–,return value
2、代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
| import java.util.Scanner;
public class StackDemo { public static void main(String[] args) { ArrayStack arrayStack = new ArrayStack(4); String key = ""; boolean loop = true; Scanner scanner = new Scanner(System.in); while (loop){ System.out.println("show:显示栈"); System.out.println("exit:退出栈"); System.out.println("push:入栈"); System.out.println("show:出栈"); key = scanner.next(); switch (key){ case "show": arrayStack.list(); break; case "push": System.out.println("请输入一个值"); int value = scanner.nextInt(); arrayStack.push(value); break; case "pop": try { int res = arrayStack.pop(); System.out.println("出栈的数据为: " + res); }catch (Exception e){ System.out.println(e.getMessage()); } break; case "exit": scanner.close(); loop = false; break; } } System.out.println("程序退出了"); } }
class ArrayStack{ private int maxSize; private int[] stack; private int top = -1;
public ArrayStack(int maxSize){ this.maxSize = maxSize; stack = new int[this.maxSize]; } public boolean isFull(){ return top == maxSize - 1; }
public boolean isEmpty(){ return top == -1; }
public void push(int value){ if(isFull()){ System.out.println("栈满"); return; } top++; stack[top] = value; } public int pop(){ if(isEmpty()){ throw new RuntimeException("栈空"); } int value = stack[top]; top--; return value; } public void list(){ if(isEmpty()){ System.out.println("栈空"); return; } for (int i = top; i >=0; i--) { System.out.printf("stack[%d]=%d\n",i,stack[i]); } }
}
|
五、哈希表(HashTable)
1、处理方法:
先用哈希函数求值,然后除数组的长度。得出余数放到相应的数组中,若有冲突,则用链表连接。(每个元素包含对应的键和值)
2、代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
| package suanfa;
import java.util.Scanner;
public class HashT { public static void main(String[] args) {
HashTable hashTable = new HashTable(7); hashTable.add(new Stu(1,"pl")); hashTable.add(new Stu(2,"zky")); hashTable.add(new Stu(3,"zl"));
String key = ""; Scanner scanner = new Scanner(System.in); while (true){ System.out.println("add:添加学生信息"); System.out.println("list:显示学生信息"); System.out.println("find:查找学生信息"); System.out.println("delete:删除学生信息"); System.out.println("exit:退出学生系统");
key=scanner.next(); switch (key){ case "add": System.out.println("输入id"); int id = scanner.nextInt(); System.out.println("输入名字"); String name = scanner.next(); Stu stu = new Stu(id,name); hashTable.add(stu); break;
case "list": hashTable.list(); break;
case "exit": scanner.close(); System.exit(0); break;
case "delete": System.out.println("输入要删除学生的id"); id = scanner.nextInt(); hashTable.Delete(id); break;
case "find": System.out.println("输入要查找学生的id"); id = scanner.nextInt(); hashTable.Find(id); break; } }
} }
class HashTable{ private StuLinkedList[] stuLinkedListArray; private int size;
public HashTable(int size){ this.size = size; stuLinkedListArray = new StuLinkedList[size]; for (int i = 0; i < size; i++) { stuLinkedListArray[i] = new StuLinkedList(); } }
public void add(Stu stu){ int stuLinkedListNo = hashFun(stu.id); stuLinkedListArray[stuLinkedListNo].add(stu); }
public void list(){ for (int i = 0; i < size; i++) { stuLinkedListArray[i].list(i); } }
public void Delete(int id){
int stuLinkedListNo = hashFun(id); Stu stu = stuLinkedListArray[stuLinkedListNo].Del(id);
if(stu != null){ System.out.println("在第" + (stuLinkedListNo+1) +"链表删除该学生信息" + id + stu.name); }else { System.out.println("没有找到该学生信息"); } }
public void Find(int id){ int stuLinkedListNo = hashFun(id); Stu stu = stuLinkedListArray[stuLinkedListNo].FindStu(id); if(stu != null){ System.out.println("在第" + (stuLinkedListNo+1) +"链表找到该学生信息" + id + stu.name); }else { System.out.println("没有找到该学生信息"); } }
public int hashFun(int id){ return id % size; } }
class Stu{ public int id; public String name; public Stu next;
public Stu(int id, String name) { this.id = id; this.name = name; } }
class StuLinkedList{ private Stu head;
public void add(Stu stu){ if(head == null){ head = stu; return; } Stu curStu = head; while (true){ if(curStu.next == null){ break; } curStu = curStu.next; } curStu.next = stu; }
public void list(int i){
if(head == null){ System.out.println(i + "号链表为空"); return; } Stu curStu = head; while (true){ System.out.printf(i + "号链表=> id = %d name = %s\t",curStu.id,curStu.name); System.out.println(); if(curStu.next == null){ break; } curStu = curStu.next; } }
public Stu FindStu(int id){ if(head == null){ System.out.println("链表为空"); return null; } Stu curStu = head; while (true){ if(curStu.id == id){ break; } if(curStu.next == null){ curStu = null; break; } curStu = curStu.next; } return curStu; }
public Stu Del(int id){ if(head == null){ System.out.println("链表为空"); return null; } Stu curStu = head; Stu delStu = null; while (true){ if(head.id == id){ delStu = head; head = null; break; } if(curStu.next.id == id){ delStu = curStu.next; break; } if (curStu.next == null){ curStu = null; break; } curStu = curStu.next; }
if(head == null){ return delStu; } else if(curStu.next.next!=null) { curStu.next = curStu.next.next; }else { curStu.next = null; } return delStu; } }
|
六、搜索二叉树
1、基本概念
节点的度:一个节点含有的子树的个数称为该节点的度; 如上图:A的为2
叶节点:度为0的节点称为叶节点; 如上图:G、H、I节点为叶节点
非终端节点或分支节点:度不为0的节点; 如上图:B、D、C、E、F节点为分支节点
双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点; 如上图:A是B的父节点
孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点; 如上图:B是A的孩子节点
兄弟节点:具有相同父节点的节点互称为兄弟节点; 如上图:B、C是兄弟节点
树的度:一棵树中,最大的节点的度称为树的度; 如上图:树的度为2
节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
树的高度或深度:树中节点的最大层次; 如上图:树的高度为4
堂兄弟节点:双亲在同一层的节点互为堂兄弟;如上图:H、I互为兄弟节点
节点的祖先:从根到该节点所经分支上的所有节点;如上图:A是所有节点的祖先
子孙:以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙
森林:由m棵互不相交的树的集合称为森林;
2、实现过程
创造一个二叉树类
- 类中有属性一个节点(为节点类的对象):根节点
- 创造一个节点的内部类
-
- 判断方法:是否为空
- 添加某个值:借助辅助节点变量,小走左大走右,找到左或右子节点为空值时插入
- 查找最大值:
- 删除某个值:
- 前序遍历:先结点(结点开始),然后从左(最小值开始)到右
- 后序遍历:先左再右、后结点
3、代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
| package 数据结构;
public class BinaryT { public static void main(String[] args) {
BinarySortTree binarySortTree = new BinarySortTree(); Node root = new Node(4,"a"); binarySortTree.add(root); binarySortTree.add(new Node(2,"b")); binarySortTree.add(new Node(3,"c")); binarySortTree.add(new Node(6,"d"));
binarySortTree.preOrder(root); System.out.println("\n========="); binarySortTree.inOrder(root); System.out.println("\n========="); binarySortTree.nextOrder(root); } }
class Node {
int no; String name; Node left; Node right; Node parent;
public Node(int no, String name) { this.no = no; this.name = name; }
public String toString() { return "node{" + "no=" + no + ", name='" + name + '\'' + '}'; } }
class BinarySortTree {
Node root;
public Node getRoot(){ return root; }
public void add(Node x) {
if (root == null) { root = x; return; }
Node temp = root;
while (true) {
if (temp.no < x.no) { if (temp.right == null) { temp.right = x; x.parent = temp; break; } else { temp = temp.right; } } else if (temp.no > x.no) { if (temp.left == null) { temp.left = x; x.parent = temp; break; } else { temp = temp.left; } } else { temp.name = x.name; break; } }
} public Node findMin(){ if (root == null) { return root; }
Node temp = root; while (true) { if(temp.left == null){ return temp; }else { temp = temp.left; } } }
public Node findMax(){ if (root == null) { return root; }
Node temp = root; while (true) { if(temp.right == null){ return temp; }else { temp = temp.right; } } }
public Node del(int no){
if(root == null || root.no ==no){ return null; }
Node temp = root; while (true){
if (temp.no < no) { if (temp.right == null) { return null; } else { temp = temp.right; } } else if (temp.no > no) { if (temp.left == null) { return null; } else { temp = temp.left; } } else { if(temp.right == null && temp.left == null){ temp.parent.left = null; temp.parent.right = null; return temp; } if(temp.right == null || temp.left == null){ if(temp.right == null){ temp.parent.left = temp.left; return temp; }else { temp.parent.right = temp.right; return temp; } }else { Node cur = temp.right; while (true) { if(cur.left == null){ break; }else { cur = cur.left; } } temp.no = cur.no; temp.name = cur.name; cur.parent.left =null; return cur; } } } }
public void preOrder(Node root) { if (root != null) { System.out.print(root.toString()+" | "); preOrder(root.left); preOrder(root.right); } }
public void inOrder(Node root) { if (root != null) { inOrder(root.left); System.out.print(root.toString()+" | "); inOrder(root.right); } }
public void nextOrder(Node root) { if (root != null) { nextOrder(root.left); nextOrder(root.right); System.out.print(root.toString()+" | "); } }
}
|
七、堆
1、堆特性:
1、堆中某个节点的值总是不大于(小顶堆)或不小于(大顶堆)其父节点的值
2、堆总是一棵完全二叉树
2、堆一般用数组实现
2、实现过程
- 构造方法
- 成员变量
- 成员方法
- 判断两个索引值的大小:[i]是否小于[j]
- 交换两个索引的值
- 删除最大元素:堆取出数据只能取出最大值,这样保证堆的特性
- 插入一个元素(先添加>再比较找到>再交换)
- 上浮算法找到正确位置
- 下浮算法为添加的数据找到正确位置
3、代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
| package 数据结构;
public class heapStruction { public static void main(String[] args) { Heap heap = new Heap(10); heap.insert(1); heap.insert(2); heap.insert(3); heap.insert(4); heap.insert(5); heap.insert(6); heap.insert(7); int result = 0; while ((result = heap.delMax()) != 0){ System.out.print(result + " "); }
}
}
class Heap{
private int[] items; private int N;
public Heap(int capacity){ this.items =new int[capacity + 1]; this.N = 0; }
private boolean less(int i ,int j){ return items[i] < items[j]; }
private void exch(int i , int j){ int temp = items[i]; items[i] = items[j]; items[j] = temp; }
public void insert(int t){ items[++N] = t; swim(N); }
private void swim(int k){ while (k>1){ if(less(k/2,k)){ exch(k/2,k); } k/=2; } }
public int delMax(){ int max = items[1]; exch(1,N); items[N] = 0; N--; sink(1); return max;
}
private void sink(int k){ while (2*k<N){ int max; if(2*k + 1 <= N){ max = less(2*k,2*k+1) ? 2*k + 1 : 2*k; }else { max = 2*k; } if(!less(k,max)){ break; } exch(k,max); k = max; }
} }
|
八、图
1、基本概念
图由一组顶点和一组能够将两个顶点相连的边组成
自环:自己连接自己
平行边:连接同一对顶点的两条边
无向图:边无方向意义
有向图:不仅连接两个顶点,且具有方向
2、相关术语
相邻顶点:通过一条边相连时,我们称这两个顶点是相邻的,并且称这两条边依附与这两个顶点
度:连接该顶点的边数
子图:一幅图所有边的子集
路径:由边顺序连接的一系列路径
环:一条路径的起点与终点相同称为环
连通图:任意一个顶点都存在一条路径到另外一个顶点
非连通图:存在顶点间无路径到达
3、实现过程
基本原理:模拟所有顶点与连接顶点的边(邻接矩阵【二维数组】、邻接表【】)
邻接矩阵【二维数组】:索引表示顶点,索引的值表示两点是否连接(内存占用较大)
邻接表【一维数组插入队列】:一维数组表示顶点,队列表示邻接点
- 构造方法
- 成员变量
-
- 成员方法
- 获取顶点的数量
- 获取边的数量
- 向图中添加一条边
- 获取和顶点相邻的所有顶点
4、代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| package 数据结构;
import java.util.ArrayList; import java.util.Arrays;
public class GraphS { public static void main(String[] args) { Graph graph = new Graph(5); String VertexValue[] = {"A","B","C","D","E"}; for (String value : VertexValue) { graph.insertVertex(value); } graph.insertEdge(0,1,1); graph.insertEdge(1,2,1); graph.insertEdge(2,3,1); graph.insertEdge(3,4,1);
graph.show(); }
}
class Graph{
private ArrayList<String> vertexList; private int[][] edges; private int numOfEdges;
public Graph(int n){ edges = new int[n][n]; vertexList = new ArrayList<String>(n); numOfEdges = 0; }
public void show(){ for (int[] link :edges) { System.out.println(Arrays.toString(link)); } }
public int getNumOfVertex(){ return vertexList.size(); } public int getNumOfEdges(){ return numOfEdges; } public String getValueByIndex(int i){ return vertexList.get(i); } public int getWeight(int v1,int v2){ return edges[v1][v2]; }
public void insertVertex(String vertex){ vertexList.add(vertex); }
public void insertEdge(int v1,int v2,int weight){ edges[v1][v2] = weight; edges[v2][v1] = weight; numOfEdges++; }
}
|
(一)图的深度优先遍历(递归)
从初始访问结点出发,初始访问结点可能有多个领接结点,深度优先遍历的策略是:
首先访问第一个邻接结点,然后再以这个被访问的领接结点作为初始结点,访问它的第一个领接结点,即每次访问完当前结点后首先访问当前结点的第一个领接结点。
实现算法步骤:
1、访问初始结点v,并标记结点v为已访问
2、查找结点v的第一个领接点w
3、若w存在则执行【4】,不存在回到【1】,从v的下一个结点继续
4、若w未被访问,重复【123】
5、若w被访问,查找结点v的领接结点w的下一个邻接结点,转到【3】
代码增加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| private ArrayList<String> vertexList; private int[][] edges; private int numOfEdges;
private boolean[] isVisited;
public Graph(int n){ edges = new int[n][n]; vertexList = new ArrayList<String>(n); numOfEdges = 0; isVisited = new boolean[n]; }
public int getFirstNeighbor(int index){ for (int j = 0; j < vertexList.size(); j++) { if(edges[index][j]>0){ return j; } } return -1; }
public int getNextNeighbor(int v1,int v2){ for (int i = v2+1; i < vertexList.size(); i++) { if(edges[v1][i]>0){ return i; } } return -1; }
private void dfs(boolean[] isVisited,int i){ System.out.print(getValueByIndex(i) + ">"); isVisited[i] = true; int w = getFirstNeighbor(i); while (w != -1){ if(!isVisited[w]){ dfs(isVisited,w); } w = getNextNeighbor(i,w); } }
public void dfs(){ for (int i = 0; i < getNumOfVertex(); i++) { if(!isVisited[i]){ dfs(isVisited,i); } } }
|
(二)图的广度优先遍历
类似于一个分层搜索的过程,广度优先遍历需要使用一个队列以保持访问过的结点的顺序,以便按这个顺序来访问这些结点的邻接结点。
实现算法步骤:
1、访问初始结点v,并标记结点v为已访问
2、结点v进入队列
3、队列非空,继续进行,否则结束
4、出队列,取得头结点u
5、查找结点u的第一个邻接结点w
6、若结点u的邻接结点w不存在,则转到步骤3;否则循环执行以下三个步骤:
6.1若结点w尚未被访问,则访问结点w并标记为已访问。
6.2结点w入队列
6.3查找结点u的继w邻接结点后的下一个邻接结点w,转到步骤6
代码增加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| private void bfs(boolean[] isVisited,int i){ int u ; int w ; LinkedList queue = new LinkedList(); System.out.print(getValueByIndex(i) + ">"); isVisited[i] = true; queue.addLast(i);
while (!queue.isEmpty()){ u = (Integer) queue.removeFirst(); w = getFirstNeighbor(u); while (w != -1){ if(!isVisited[w]){ System.out.print(getValueByIndex(w) + ">"); isVisited[w] = true; queue.addLast(w); } w = getNextNeighbor(u,w); } } }
public void bfs(){ for (int i = 0; i < getNumOfVertex(); i++) { if(!isVisited[i]){ bfs(isVisited,i); } } }
|