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;
}
}

京公网安备 11010502036488号