链表
链表是一种递归的数据结构,它或者为空(null),或者是指向一个节点的引用,该节点含有一个泛型的元素和一个指向另一条链表的引用。
在面向对象的编程中,实现链表并不困难。
public class MyNode<E> {
MyNode<E> next;
E item;
}
一个Node对象含有两个实例变量,类型分别为Item和MyNode。
Item表示值,而如果first是一个指向某个MyNode对象的变量,我们可以使用first.item和first.next访问它的实例变量。
构造链表
根据递归定义,我们只需要一个Node类型的变量就能表示一条链表,只要保证它的值是null或者指向另一个Node对象且该对象的next域指向了另一条链表即可。
MyNode first= new MyNode();
MyNode second= new MyNode();
First.item =“a”;
Second.item = “b”;
First.next = second;
向链表中添加节点
先建立一个节点
MyNode<E> node = new MyNode<E>(item);
判断条件
if(first==null){
//如果头部为空
first = node ;
}else if(last !=null){
//如果尾部不为空
last.next = node;
}
最后size加一
last = node;
size++;
从链表中删除节点
删除元素等要用到索引的地方,要先判断是否角标越界。
if (index < 0 || index > size) {
try {
throw new Exception("角标越界");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
在这里可以抛出一个异常。
MyNode<E> pre = first;
E result = null;
//得到目标的前一个元素
for(int i=0;i<index-1;i++){
pre = pre.next;
}
//如果删除头部
if(index==0){
result = first.item;
first = first.next;
pre = null;
}
//如果删除尾部
else if(index==size-1){
result = last.item;
pre.next = null;
last = pre;
}
//如果删除中间的
else{
MyNode<E> self = pre.next;
result = self.item;
pre.next = self.next;
self = null;
}
size--;
return result;
向链表中插入节点
MyNode<E> node = new MyNode<E>(item);
MyNode<E> pre = first;
for(int i=0;i<index1;i++){
pre = pre.next;
}
//这里判断是否在头部插入
if(index2==0) {
node.next = pre;
first = node;
}else {
node.next = pre.next ;
pre.next = node;
node.item = item;
}
size++;
改变元素
MyNode<E> result = first;
for(int i = 0;i<index;i++){
//遍历到当前的元素索引
result = result.next;
}
result.item = item;
得到元素
MyNode<E> result = first;
//遍历到当前的元素索引
for(int i = 0;i<index;i++){
result = result.next;
}
return result.item;
上述介绍的是单向链表,双向链表只不过比单向的多前驱和后继而已。
添加节点(相对于单向链表)
if (last != null) {
last.next = node;
node.pre = last;
}
删除节点
if (index == 0) {
result = first.item;
first = first.next;
first.pre = null;
}
else if (index == size - 1) {// 删除尾部
// 找到最后一个元素。给结果值赋值
result = last.item;
before.next = null;
last = before;
} else {// 删除中间的
// 首选要找到删除节点
MyNode<E> self = before.next;
result = self.item;
before.next = self.next;
self.next.pre = before;
self = null;
}
插入节点
if (index == 0) {
myNode.next = before;
before.pre = myNode;
first = myNode;
size++;
} else {
myNode.next = before.next;
before.pre = myNode;
before.next = myNode;
myNode.pre = before;
}
二叉树
树:是由n(n>=1)个有限节点组成一个具有层次关系的集合
树术语
节点度:一个节点含有子树的个数称为该节点的度
树的度:一棵树中,最大的节点的度为树的度
叶子节点:度为零的节点
父亲节点:若一个节点含有子节点,则当前节点为改子节点的父亲节点
子节点:一个节点含有子树,则子树的根节点为改节点的子节点
兄弟节点:具有相同父亲节点的子节点互为兄弟节点
节点层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推
树的深度(高度):树中节点最大的层次
其他:堂兄弟节点、子孙、森林
无序树:树中的节点次序是没有规律的
有序树:指树中同层结点从左到右有次序排列,这样的树称为有序树。
1)二叉树:每个节点最多含有两个子树的树称为二叉树
2)非二叉树:所有不是二叉树的树都属于非二叉树
二叉树还分为完全二叉树和满二叉树
满二叉树是二叉树的父节点都有左孩子和右孩子
完全二叉树是子节点呈左右左右排列
创建一棵树首先要构建森林
要在另一个类中创建左右节点还有树的值
TreeNode leftTree;
TreeNode rightTree;
int value;
构建森林
for(int i =0;i<arr.length;i++) {
将元素装到容器里
TreeNode treenode = new TreeNode(arr[i]);
list.add(treenode);
}
构建除最后一个父节点其他的父节点和孩子
for(int i =0;i<list.size()/2-1;i++) {
list.get(i).setLeftTree(list.get(2*i+1));
list.get(i).setRightTree(list.get(2*i+2));
}
//将最后一个节点单独处理
int lastIndex = list.size()/2-1;
list.get(lastIndex).setLeftTree(list.get(2*lastIndex+1));
//这里是判断是否为满二叉树
if(list.size()%2==1) {
list.get(lastIndex).setRightTree(list.get(2*lastIndex+2));
}
以上,一颗二叉树构建完毕
树的遍历
先序遍历树
先访问根节点,然后访问左子树,最后访问右子树
将树作为参数传入方法中
public void beforeSearch(TreeNode tn) {
//根
System.out.println(tn.getValue());
//左
if(tn.getLeftTree()!=null) {
beforeSearch(tn.getLeftTree());
}
//右
if(tn.getRightTree()!=null) {
beforeSearch(tn.getRightTree());
}
}
中序遍历树
先访问左子树,然后访问根节点,最后访问右子树
public void midSearch(TreeNode tn) {
//左
if(tn.getLeftTree()!=null) {
midSearch(tn.getLeftTree());
}
//根
System.out.println(tn.getValue());
//右
if(tn.getRightTree()!=null) {
midSearch(tn.getRightTree());
}
}
后续遍历树
先访问左子树,然后访问右子树,最后访问根节点
public void lastSearch(TreeNode tn) {
//左
if(tn.getLeftTree()!=null) {
lastSearch(tn.getLeftTree());
}
//右
if(tn.getRightTree()!=null) {
lastSearch(tn.getRightTree());
}
//根
System.out.println(tn.getValue());
}