連結串列和樹
連結串列
連結串列是一種遞迴的資料結構,它或者為空(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
判斷條件
if(first==null){
//如果頭部為空
first = node ;
}else if(last !=null){
//如果尾部不為空
last.next = node;
}
最後size加一
last = node;
size++;
從連結串列中刪除節點
刪除元素等要用到索引的地方,要先判斷是否角標越界。
if (index < 0 || index
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());
}