1. 程式人生 > >簡單的演算法(1)--從尾到頭列印連結串列

簡單的演算法(1)--從尾到頭列印連結串列

目錄

1、java實現

1.1、遞迴

1.1.1、測試(完整原始碼)

1.2、利用棧來實現

1.2.1、測試

2、C語言

2.1、先將連結串列反轉,再從頭輸出(改變連結串列的結構)

2.2、利用棧的“先進後出”特性


 

1、java實現

連結串列的定義:

 public class ListNode {
        int val;
        ListNode next = null;

        ListNode(int val) {
            this.val = val;
        }
}

1.1、遞迴

public class Solution {
    ArrayList<Integer> arrayList=new ArrayList<Integer>();
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        if(listNode!=null){
            this.printListFromTailToHead(listNode.next);
            arrayList.add(listNode.val);
        }
        return arrayList;
    }
}  

 此方式雖然看起來簡潔,如果連結串列很長時,就會導致函式的呼叫層級很深,有可能會導致函式棧溢位。

1.1.1、測試(完整原始碼)

import java.util.ArrayList;

/**
 * @Auther: zj
 * @Date: 2018/11/6 17:18
 * @Description: 從尾到頭列印連結串列
 */
public class t7 {
//測試
    public static void main(String[] args) {

        ListNode listNode = new ListNode( 1 );
        listNode.next = new ListNode( 3 );
        listNode.next.next = new ListNode( 5 );

        ListNode head=listNode;

        while (head!=null){
            System.out.print( head.val+"->" );
            head=head.next;
        }

        System.out.print( "\n" );

        Solution s= new Solution();
        System.out.println( s.printListFromTailToHead( listNode ) );

    }
}

//定義連結串列
class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}

//從尾到頭列印連結串列
class Solution {
    ArrayList<Integer> arrayList=new ArrayList<Integer>();
      ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        if(listNode!=null){
            this.printListFromTailToHead(listNode.next);
            arrayList.add(listNode.val);
        }
        return arrayList;
    }
}

1.2、利用棧來實現

//法2:利用棧來
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        Stack<Integer> stack = new Stack<Integer>();
        while(listNode!=null) {
            stack.push(listNode.val);
            listNode=listNode.next;
        }
        ArrayList<Integer> arrayList = new ArrayList<Integer>();
        while(!stack.isEmpty()){
            arrayList.add(stack.pop());
        }
        return arrayList;
    }

1.2.1、測試

import java.util.ArrayList;
import java.util.Stack;

/**
 * @Auther: zj
 * @Date: 2018/11/6 17:18
 * @Description: 從尾到頭列印連結串列
 */
public class t7 {
    public static void main(String[] args) {

        ListNode listNode = new ListNode( 1 );
        listNode.next = new ListNode( 3 );
        listNode.next.next = new ListNode( 5 );

        ListNode head=listNode;

        while (head!=null){
            System.out.print( head.val+"->" );
            head=head.next;
        }

        System.out.print( "\n" );

        Solution s= new Solution();
        System.out.println( s.printListFromTailToHead( listNode ) );

    }
}

//定義連結串列
class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}


//法2:利用棧來
class  Solution {
    ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        Stack<Integer> stack = new Stack<Integer>();
        while(listNode!=null) {
            stack.push(listNode.val);
            listNode=listNode.next;
        }
        ArrayList<Integer> arrayList = new ArrayList<Integer>();
        while(!stack.isEmpty()){
            arrayList.add(stack.pop());
        }
        return arrayList;
    }
}

2、C語言

與java類似

2.1、先將連結串列反轉,再從頭輸出(改變連結串列的結構)

從頭到尾輸出比較簡單,於是我們很自然地想到把連結串列中連結結點的指標反轉過來,改變連結串列的方向,就可以從頭到尾輸出了。

#include<stdio.h>
#include<stdlib.h>
//連結串列的相關操作

//定義連結串列的結構
typedef struct LNode *PtrToLNode;
struct LNode {
    int data;//資料域,用於儲存資料
    PtrToLNode Next;//指標,可以用來訪問節點資料,也可以遍歷,指向下一個節點
};

//初始化
PtrToLNode init(int n) {
    PtrToLNode head,node,end;//定義頭節點,普通節點,尾部節點;
    head = (PtrToLNode)malloc(sizeof(struct LNode));
    scanf("%d",&(head->data));//頭指標賦值
    end =head;
    for(int i=0;i<n;i++) {//新增結點
        node = (PtrToLNode)malloc(sizeof(struct LNode));
        scanf("%d",&(node->data));
        end->Next=node;
        end=node;
    }
    end->Next = NULL;//結束建立
    return head;
}

//反轉單鏈表
PtrToLNode reverseLNode(PtrToLNode head) {
    if(head==NULL||head->Next==NULL) //少於兩個節點沒有反轉的必要
        return head;
    PtrToLNode p,q,r;

    p= head;
    q=head->Next;
    head->Next=NULL;//舊的頭指標是新的尾指標,next需要指向NULL
    while(q) {
        r=q->Next; //先保留下一個step要處理的指標
        q->Next=p;//然後p q交替工作進行反向
        p=q;
        q=r;
    }
        head=p;// 最後q必然指向NULL,所以返回了p作為新的頭指標
    return head;
}

int main(void) {
    int n=3;
    PtrToLNode head = init(n);//連結串列初始化&&連結串列賦值
    PtrToLNode node=head;
    while(node!=NULL) {
        printf("%d->",node->data);//列印連結串列
        node = node->Next;
    }
    printf("\n反轉連結串列:\n");
    PtrToLNode end =reverseLNode(head);//反轉連結串列
    while(end!=NULL) {
        printf("%d->",end->data);
        end=end->Next;
    }
    return 0;
}

2.2、利用棧的“先進後出”特性

#include<stdio.h>
#include<stdlib.h>
//連結串列的相關操作

//定義連結串列的結構
typedef struct LNode *PtrToLNode;
struct LNode {
    int data;//資料域,用於儲存資料
    PtrToLNode Next;//指標,可以用來訪問節點資料,也可以遍歷,指向下一個節點
};

//定義棧的結構
typedef struct StackNode *PtrToStack;
struct StackNode {
    int data;
    PtrToStack Next;
};

//連結串列初始化及賦值
PtrToLNode init(int n) {
    PtrToLNode head,node,end;//定義頭節點,普通節點,尾部節點;
    head = (PtrToLNode)malloc(sizeof(struct LNode));
    scanf("%d",&(head->data));//頭指標賦值
    end =head;
    for(int i=0;i<n;i++) {//新增結點
        node = (PtrToLNode)malloc(sizeof(struct LNode));
        scanf("%d",&(node->data));
        end->Next=node;
        end=node;
    }
    end->Next = NULL;//結束建立
    return head;
}

//棧的初始化
PtrToStack createStack() {
    PtrToStack head;
    head = (PtrToStack)malloc(sizeof(struct StackNode));
    head->Next=NULL;
    return head;
}
//判斷棧是否為空
int IsEmpty(PtrToStack s) {
    if(s->Next==NULL) {
        return 1;
    } else {
        return 0;
    }
}
//壓棧
void Push(PtrToStack s,int X) {
    PtrToStack tmp = (PtrToStack)malloc(sizeof(struct StackNode));
    tmp->data=X;
    tmp->Next=s->Next;
    s->Next=tmp;
}
//出棧
int Pop(PtrToStack s) {//棧頂
    PtrToStack FirstCell;
    int tmp;

    if(IsEmpty(s)) {
        printf("該堆疊為空");
        return -1;
    } else {
        FirstCell = s->Next;
        tmp = FirstCell->data;
        s->Next=FirstCell->Next;
        free(FirstCell);
    }
    return tmp;

}

int main(void) {
    int n=3;
    PtrToLNode head = init(n);//連結串列初始化&&連結串列賦值
    PtrToLNode node=head;
    while(node!=NULL) {
        printf("%d->",node->data);//列印連結串列
        node = node->Next;
    }

    printf("\n利用棧反向輸出連結串列:\n");

    PtrToStack stack_head=createStack();
    PtrToLNode bbb=head;
    while(bbb!=NULL) {
        printf("%d\n",bbb->data);
        Push(stack_head,bbb->data);//入棧
        bbb = bbb->Next;
    }

    PtrToStack stack_bbb=stack_head;
    printf("\n列印棧:\n");
    PtrToStack ccc=stack_head->Next;//剔除棧頂元素
    while(ccc!=NULL) {
        printf("%d->",ccc->data);
        ccc = ccc->Next;
    }
    return 0;
}

非常簡單的題目,就是容易錯:p