1.链表的翻转
思路:
原地算法: 不借助外在的存储空间,首先使用头插法,在链表的头部插入节点,每一轮循环插入一个节
class Node( int data; Node next; ) public void test(Node head){ Node temp = null; Node nextnode = null; while(head != null){ nextnode = head.next; head.next = temp; temp = head; head = nextnode; } }
借助外部结构: 使用栈来实现链表的翻转
public void test(Node head){ Stack stack = new Stack(); while(head != null){ stack.push(head.data); head = head.next; } while(!stack.isEmpty()){ System.out.println(stack.pop()); } }
2.判断链表是否有环,以及环的入口
思路:
使用Floyed算法来判断链表时候有环,即使用两个指针,以不同的速度前进,如果链表没有环,则两个指针不会相遇,如果有,则会在某一个时刻相遇
public Boolean test(Node head){ Node head1 = head ; Node head2 = head; while(head != null){ head1 = head.next; head2 = head.next.next; if(head1 == head2) return true; } return false; }
思路:
对于环的入口,首先我们设置两各指针,一个快(兔子)一个慢(乌龟),假设当兔子和乌龟在环里相遇,则这个时候,兔子已经在环内跑了n圈,每圈的长度为L,假设乌龟在进行环之前跑了k的路,进入环之后,跑了x之后与兔子相遇,所以等式: 2(k + x) = k + nL + x => k + x = nL.
故: 乌龟从起点跑到循环入口的距离为: nL - x
又:此时将兔子的速度和乌龟一样,则兔子在圈内跑n-1圈之后,又会回到和乌龟相遇的点,只要在跑L-x的路,就可以回到下一轮循环的起点.
即:(n-1)L + (L-x) = nL - x
int FindLoop(Node head){ Node slow = head; Node fast = head; int loopExists = 0,count =0; while(slow && fast && fast.next){ slow = slow.next; fast = fast.next.next; if(slow == fast ){ loopExists = 1; break; } } if(loopExists){ fast = fast.next; while(slow != fast){ fast = fast.next; couter++; } return counter; } return 0; //不存在环 }
3.栈来模拟队列
思路:
队列的特性是FIFO,栈的特性是FILO,因此使用栈来模拟队列,则使用两个栈来运行,栈1,栈2,当进行入队操作时,则往栈1中push元素,当进行出队的时候,将栈1中的元素出栈并压栈到栈2中,然后进行出栈操作,在完后的出队是,需要注意的是,先要判断栈2中时候有元素,若有有,则从栈2出栈,没有的话,则将栈1的元素出栈然后压栈到栈2,在进行出栈.
public void line(){ Stack stack1,stack2; //入队 public void enqueue(int data){ stack1.push(data); } public void dequeue(){ if(!stack2.isEmpty()){ stack2.pop(); }else{ if(!stack1.isEmpty()){ while(!stack1.isEmpyt()){ stack2.push(stack.pop()); } stack2.pop(); }else{ return null; } } } }
4.使用队列模拟栈
思路:
栈的特性是FILO,队列的特性是FIFO,使用;两个队列q1,q2, 当进行压栈操作时,对q1执行入队操作,当进行出栈操作时,首先将q1中前n-1个元素出队并入队到q2中,然后将q1中的元素出队,注意必须保证一个队列是空的,当进行压栈的时候,对有数据的队列进行入队。
public void test(){ Queue queue1 ,queue2; static count = 0; public void push(int data){ queue1.queue(data); count ++; } public void pop(){ if(count == 0 ){ ; }else if(count == 1){ queue1.deque(); count--; }else{ while(count > 1){ queue2.queue(queue1.deque()); count--; } queue1.deuque(); switch(queue1,queue2); } } }
5.树的前序,中序遍历
思路:(非递归)
使用栈的数据结构来进行树的输出
class Node { int value; Node left; Node right; } 前序 public void print(Node root){ Stack<Node> stack = new Stack<Node>(); while(1){ while(root!= null){ System.out.println(root.value); stack.push(root); root = root.left; } if(stack.isEmpty() == null) break; root = stack.pop(); root = root.rigth; } } 中序 public void print2(Node root){ Stack<Node> stack = new Stack<Node>(); while(1){ while(root != null){ stack.push(root); root = root.left; } if(stack.isEmpty == null) break; root = stack.pop(); System.out.println(root.value); root = root.right; } }
6.分层遍历
思路:
使用队列存储节点
public void print3(Node root){ Queue<Node> Que = new Queue<Node>(); Que.queue(root); Node temp = null; while(!Que.isEmpyt()){ temp = Que.Deque(); System.out.println(temp.value); if(temp.left != null) Que.queue(temp.left); if(temp.right != null) Que.queue(temp.right); } }
7.从遍历顺序遍历二叉树
思路:
使用队列和栈
public void print4(Node root){ Stack<Node> Sta = new Stack<Node> (); Queue<Node> Que = new Queue<Node> (); Que.queue(root); Node temp = null; while(!Que.isEmpyt()){ temp = Que.Deque(); Stack.push(temp); if(temp.right != null) Que.queue(temp.right); if(temp.left != null) Que.queue(temp.left); } while(!Sta.isEmpty()) System.out.println(Sta.pop()); }
8.曲折遍历二叉树
思路:
使用两个栈解决问题
public void ZigZag(Node root){ Node temp; int leftToRight = 1; if(root == null) return; Stack CurrentLevel = new Stack(); Stack NextLevel = new Stack(); CurrentLevel.push(root); while(!CurrentLevel.isEmpty()){ temp = CurrentLevel.pop(); if(temp != null){ System.out.println(temp.value); if(leftToRight == 1 ){ if(temp.left != null) NextLevel.push(temp.left); if(temp.right != null) NextLevel.push(temp.right); }else{ if(temp.right != null) NextLevel.push(temp.right); if(tmep.left != null) NextLevel.push(temp.left); } } if(CurrentLevel.isEmpty()){ leftToRight = 1- leftToRight; swap(CurrentLevel,NextLevel); } } }
9.线索二叉树的后继节点和前驱节点
思路:
为了节省每个Node节点的空间,引出线索二叉树,即每个Node有一个前驱节点,又有一个后继节点,根据不同的遍历方式,其前驱节点和后继节点也不同,
class Node{ int Value; int tagleft; int tagrihgt; Node left; Node right; }
当tagleft,tagright为0时,表示没有前驱或后继节点,则left,right则分别指向其指定遍历顺序的前驱和后继节点.
10.二叉搜索树的节点的插入
思路:
如果没有指定插入的位置,则将新的节点插入到空闲位置,
如果有指定插入的位置,则进行比较,然后插入到合适的位置.
//没有任何插入约束 public void insert(Node root, Node value){ Node node = new Node(vlaue); node.left = node.rihgt = null; Queue Que = new Queue(); Que.queue(root); Node temp = null; if(!Que.isEmpty()){ tmep = Que.Deuqe(); if(temp.left == null){ temp.left = node; break; }else{ Que.queue(temp.left); } if(temp.right == null){ temp.right = node; break; }else{ Que.queue(temp.right); } } }
//将元素插入到二叉查找树中 public void insert(Node root,Node value){ Node node = new Node(value); Queue Que = new Queue(); Que.queue(root); Node temp = null; while(!Que.isEmpty()){ temp = Queue.Deque(); if(temp.value > node.value){ if(temp.left == null){ temp.left = node; }else{ Que.queue(temp.left); } }else{ if(temp.right == null){ temp.right = node; }else{ Que.queue(temp.right); } }else{ System.out.println(“已存在”); break; } } }
11.二叉搜索树删除节点
思路:
对于二叉树的节点,分3中情况:
当被删除的节点是叶子节点,则将其父节点的左右指针变为NULL;
当被删除的节点有一个子节点,则找出删除节点的父节点,把子节点直接设置成父节点的子节点;
当被删除的节点有两个子节点,则在左子树中找到数值最大的那个节点,并用它的键来替换删除节点的键.然后对失去的节点运行满足条件的规则.
12.平衡二叉树的平衡问题
思路:
平衡二叉树是一种为了防止单节点二叉树的查找问题,即二叉树中每层只有一个节点,这样在查找的的复杂度比较高,因为引出平衡二叉树,节点的左子树和右子树的高度之差小于等于1.
只需要把首个失去平衡的节点修复好之后,AVL树性质都会自动回复,我们把需要恢复平衡的节点记为X,因为有以下几种情况:
-
当向X的左侧节点的左子树插入元素,LL旋转
public void rotatell(Node x){ Node w = x.left; x.left = w.right; w.right = x; x.height = max(height(x.left),height(x.right)) + 1; w.height = max(height(w.left),height(w.right)) + 1; }
2. 当向X的右侧节点的右子树插入元素,RR旋转
public void rotaterr(Node x){ Node w = x.right; x.right = w.left; w.left = x; x.height = max(height(x.left),height(x.right)) + 1; w.height = max(height(w.left),height(w.right)) + 1; }
-
当向X的左侧子节点的右子树插入元素,即LR旋转,需要旋转两次
public void rotate(Node z ){ z.left = rotaterr(z.left); rotatell(z.left); }
-
当向X的右侧子节点的左子树插入元素,即RL旋转,需要旋转两次
public void rotate(Node z){ z.right = rotatell(z.right); rotate(z.right); }
13.堆化
思路:
堆:即节点要么大于子节点(大根堆),要么小于子节点(小根堆),可用于排序
堆的存储可以使用数组进行存储:
class head{ int count; int capacity; int heap_type; int [] array; }
堆化:向下渗透
void down(head h,int i){ int l,r,max,temp; l = leftChild(h,i); r = rightChild(h,i); if(l != -1 && h.array[l] > h.array[i]){ max = l; }else{ max = i; } if(r != -1 && h.array[r] > h.array[max]){ max = r; } if(max != i){ temp = h.array[i]; h.array[i] = h.array[max]; h.array[max] = temp; down(h.max); } }
插入元素: 向上渗透
将新元素放入到堆的末尾,
自下而上的执行堆化,直至到达根节点为止.
public int insert(head h,int data){ if(h.count == h.capacity) resizeHead(h); int i= h.count++; while( i> 1 && data > h.array[(i-1)/2]){ h.array[i] = h.array[(i-1)/2]; i = (i-1)/2; } h.array[i] = data; }
删除元素:
只需要删除掉根元素,这是标准(最大)二叉堆所需支持的唯一一种删除操作,删除根元素后,把数组里的最后一个元素复制到0号位置,也就是复制到根所在的位置.
public int delete(head h){ int data; if(h.count == 0) return -1; data = h.array[0]; h.array[0] = h.array[h.count-1]; h.count--; down(h,0); return data; }
14.排序
14.1冒泡排序
public void sort(int[] array,int n){ for(int i = 0 ;i<n ;i++){ for(int j = 1; j < n ; j++){ int temp; if(array[i] < array[j]){ temp = array[i]; array[i] = array[j]; array[j] = temp; } } } }
14.2选择排序
public void sort(int [] array,int n){ int min,temp; for(int i = 0 ; i< n -1 ; i++){ min = i; for(int j = i+1; j< n ;j++){ if(array[j] < array[min]) min = j; } temp = array[min]; array[min] = array[i]; array[i] = temp; } }
14.3插入排序
public void sort(int [] array,int n){ for(int i = 1 ;i< n ;i++){ int temp = array[i]; int j = i; while(array[i-1] > temp && j >= 1){ array[i] = array[i+1]; j--; } array[j] = temp; } }
14.4希尔排序(递减增量排序)
public void sort(int [] arrray, int n){ for(int h = 1; h < n /3 ; h = 3*h+1); for(; h > 0 ; h = h/3){ for(int i = h; i < n-1;i +=1){ v = array[i]; j = i; while(j >= h && array[j-h] > v){ array[j] = array[j-h]; j-=h; } array[j] = v; } } }
14.5快速排序
public void sort(int[] array,int low,int length){ int pivot; if(hight > low){ pivot = Partition(array,low,hight); sort(array,low,pivot-1); sort(arrry,pivot+1,hight); } } public int Partition(int[] array,int low, int high){ int left,right,pivot_item = array[low]; left = low; right = high; while(left < right){ while(array[left] <= pivot_item) left++; while(array[right] >= privot_item) right--; if(left < right) swap(array,left,right); } array[low] = array[right]; array[right] = pivot_item; return right; }
14.6堆排序
public void sort(int[] array,int n){ Head head = new Head(); int old_size ,i ,temp; buildHead(head,array,n); old_size = head.count; for(int i = n-1 ; i>0 ; i++){ temp = head.array[0]; head.array[0] = head.array[head.count-1]; (head.array[head.count-1]) = temp; head.count--; down(head,0); } head.count = old_size; }
14.7计数排序
public void sort(int[] X,int n ,int[] Y,int K){ int [] Z = new int [K],i,j; for(int i = 0;i< K,i++) Z[i] = 0; for(int j = 0;j<n;j++) Z[X[j]] = Z[X[j]] + 1; for(int i = 1; i< K; i++) Z[i] = Z[i] + Z[i-1]; for(int j = n-1;j>=0;j--){ Y[Z[X[j]]-1] = X[j]; Z[X[j]] = Z[X[j]]-1; } }