單鏈表
1.刪除單鏈表中的指定節點:
public static void deleteNode(Node head,Node node){
//刪除尾節點,采用順序查找找到尾節點的前一節點
if(node.next == null){
while(head.next!=node){
head = head.next;
}
head.next = null;
}
//要刪除的節點是頭結點
else if(head==node){
head = null;
}
//要刪除的節點是中間的普通節點
else{
Node q = node.next;
node.data = q.data;
node.next = q.next;
}
}
2.單鏈表中刪除指定數值的節點方法一:利用棧
public Node removeValue1(Node head,int num){
Stack<Node> stack = new Stack<Node>();
while(head !=null){
if(head.data!=null){
stack.push(head);
}
head = head.next;
}
while(!stack.isEmpty()){
stack.peek().next = head;
head = stack.pop();
}
return head;
}
3.單鏈表中刪除指定數值的節點方法二:不利用棧
public Node removeValue2(Node head,int num){
while(head!= null){
if(head.data!=null){
break;
}
head = head.next;
}
Node pre = head;
Node cur = head;
while(cur!=null){
if(cur.data == num){
pre.next = cur.next;
}else{
pre = cur;
}
cur = cur.next;
}
return head;
}
4.刪除單鏈表中數值重復出現的節點
public void deleteDuplication(Node head){
if(head == null){
return ;
}
HashSet<Integer> set = new HashSet<Integer>();
Node pre = head;
Node cur = head.next;
set.add(head.data);
while(cur!=null){
if(set.contains(cur.data)){
pre.next = cur.next;
}else{
set.add(cur.data);
pre = cur;
}
cur = cur.next;
}
}
5.兩個單鏈表生成相加鏈表
public Node addList2(Node head1,Node head2){
Stack<Integer> stack1 = new Stack<Integer>();
Stack<Integer> stack2 = new Stack<Integer>();
while(head1!= null){
stack1.push(head1.data);
head1 = head1.next;
}
while(head2!= null){
stack2.push(head2.data);
head2 = head2.next;
}
int n1 = 0;//鏈表1的數值
int n2 = 0;//鏈表2的數值
int n = 0;//n1+n2+ca
int ca = 0;//進位
Node node = nul;//當前節點
Node pnode= null;//當前節點的前驅節點
while(!stack1.isEmpty()||!stack2.isEmpty()){
n1 = stack1.isEmpty()?0:stack1.pop();
n2 = stack2.isEmpty()?0:stack2.pop();
n = n1+n2+ca;
node = new Node(n%10);
node.next = pnode;
pnode = node;
ca = n/10;
}
if(ca == 1){
pnode = node;
node = new Node(n/10);
node.next = pnode;
}
return node;
}
6.判斷一個單鏈表是否為回文結構(1221反轉1221是回文結構,1234反轉4321不是回文結構)
public boolean isPalindeome1(Node head){
if(head == null){
retrun false;
}
Stack<Node> stack = new Stack<Node>();//記住這個地方不是cur.next不然最后一個節點沒有壓入棧
Node cur = head;
while(cur!=null){
stack.push(cur);
cur = cur.next;
}
while(head.next!=null){
if(head.data != stack.pop().data){
return false;
}
head = head.next;
}
return true;
}
7.刪除單鏈表的倒數第k個節點
public static Node removeLastKthNode(Node head,int k){
if(k<=0||head == null){
return head;
}
Node p = head;
for(int i = 0; i<k,i++){
if(p.next !=null){
p = p.next;
}else{
return head;
}
}
Node q = head;
while(p.next){
p = p.next;
q = q.next;
}
q.next = q.next.next;
return head;
}
8.通過兩個棧來實現一個隊列
棧 先進后出;隊列 先進先出
public class QueueWithStack{
private static Stack<Object> stack1 = new Stack<Object>();
private static Stack<Object> stack2 = new Stack<Object>();
//加入隊列中的元素只加入到棧1中
public static void appendTail(Object item){
stack.push(item);
System.out.println(“壓入棧元素”+item);
}
//刪除一個元素是,檢查棧2是夠為空,棧2不為空則彈出棧2棧頂元素
//棧2為空,則把棧1中的元素全部彈出,壓入到棧2中,然后從棧2棧頂彈出元素
public static void deleteHead(){
if(!stack2.empty()){
System.out.println(“彈出棧元素”+stack.pop());
}else{
if(stack.empty()){
throw new RuntimeException("隊列為空");
}
while(!stack1.empty()){
Object item = stack1.pop();
stack2.push(item);
}
}
}
}
9.設計含最小函數min()的棧,要求min,push,pop的時間復雜度都是0(1),min方法的作用是::就能返回是棧中的最小值
public class MinStack{
Stack<Integer> stack = new Stack<Integer>();//用來存儲數據的棧
Stack<Integer> minStack = new Stack<Integer>();//用來存儲最小數據的棧
//添加數據,首先是王stack棧中添加,如果最小minStack為空,或者棧頂的元素
//比新添加的元素要大,則將新元素也要添加到輔助棧中
public void push(int code){
stack.push(node);
if(minStack.isEmpty()||((int)minStack.peek())>=node){
minStack.push(node);
}
}
//如果stack空,直接返回
//如果stack不為空,得到棧頂元素,同時棧頂元素彈出
//如果最小棧的棧頂元素與stack彈出的元素相等,那么最小站也要將其彈出
public void pop(){
if(stack.isEmpty()){
return;
}
int node = (int)stack.peek();
stack.pop();
if((int)minStack.peek()==node){
minStack.pop();
}
}
//查看棧的最小元素
public int min(){
return (int)minStack.peek();
}
}
10.分層遍歷二叉樹,寬度優先遍歷
public static void levelTraversal(Treenode root){
if(root == null){
return;
}
LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
queue.push(root);
while(!queue.isEmpty()){
TreeNode cur = queue,removeFirst();
System.out.print(cur.val+"");
if(cur.left!=null){
queue.add(cur.left);
}
if(cur.right!=null){
queue.add(cur.right);
}
}
}
11.分層便利應用:按層打印二叉樹
public ArrayList<Integer> printFromTopToBottom(TreeNode root){
ArrayList<Integer> list = new ArrayList<Integer> ;
Queue<TreeNode> queue = new ArrayBlockingQueue<>(100);
TreeNode last = root;//當前行的最后節點
TreeNode nLast = root;//下一行的最右節點
queue.add(root);
while(!queue.isEmpty()){
TreeNode out = queue.poll();
System.out.print(out.val+"");
list.add(out.val);
if(out.left !=null){
queue.add(out.left);
nLast = out.left;
}
if(out.right !=null){
queue.add(out.right);
nLast = out.right;
}
if(out==last){
System.out.print("");
last = nLast;
}
}
return list;
}
12.前序遍歷
//(遞歸)
public static void preorderTraversalRec(TreeNode root){
if(root == null){
return;
}
System.out.print(root.val+" ");
preorderTraversalRec(root.left);
preorderTraversalRec(root.right);
}
//(迭代)
public static void preorderTraversal(TreeNode root){
if(root == null){
return;
}
Stack<TreeNode> stack = new Stack<TreeNode>();
stack.push(root);
while(!stack.isEmpty()){
TreeNode cur = stack.pop();//出棧棧頂元素
System.out.print(cur.val+" ");
//關鍵點,要先壓入右孩子,再壓入左孩子,這樣在出棧時會先打印左孩子再打印右孩子
if(cur.right!=null){
stack.push(cur.right);
}
if(cur.left!=null){
stack.push(cur.left);
}
}
}
13.中序遍歷算法
//遞歸
public static void inorderTraversalRec(TreeNode root){
if(root == null){
return;
}
inorderTraversalRec(root.left);
System.out.print(root.val+" ");
inorderTraversalRec(root.right);
}
//迭代
public static void inorderTraversal(TreeNode root){
if(root == null){
return;
}
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode cur = root;
if(cur!=null){
while(!stack.isEmpty()||cur!=null){
if(cur!=null){
stack.push(cur);
cur = cur.left;
}else{
cur = stack.pop();
System.out.print(cur.val+" ");
cur = cur.right;
}
}
}
}
14.后序遍歷算法(迭代)
public static void postorderTraversal(TreeNode root){
if(root == null){
return;
}
Stack<TreeNode> s = new Stack<TreeNode>();//第一個stack用于添加node和他的左右孩子
Stack<TreeNode> output = new Stack<TreeNode>();//第二個stack用于翻轉第一個stack輸出
s.push(root);
while(!s.isEmpty()){//確保所有元素都被翻轉到第二個stack
TreeNode cur = s.pop();//把棧頂元素添加到第二個stack中
output.push(cur);
if(cur.left!=null){//把棧頂元素的左右孩子分別添加入第一個stack
s.push(cur.left);
}
if(cur.right!=null){//把棧頂元素的左右孩子分別添加入第一個stack
s.push(cur.right);
}
}
while(!output.isEmpty()){//遍歷輸出第二個stack,即為后序遍歷
System.out.print(output.pop().val+" ");
}
}