算法與數據結構系列之[鏈表]

在這裏插入圖片描述
上一篇介紹了線性表的順序存儲結構,順序存儲結構的最大缺點就是插入和刪除時需要移除大量元素,如果要插入或刪除的數據量很大的話,執行程序的時間就會很長,造成一定的性能消耗,且線性表的順序存儲結構如動態數組,棧和隊列,底層依託靜態數組,需要通過擴容解決固定容量問題。由於順序結構的以上問題,鏈表的優勢就凸顯出來,鏈表是最簡單的動態數據結構,不需要處理固定容量問題,且插入和刪除元素,不需要移動其他元素,所以對於大數據量的頻繁插入和刪除操作,使用鏈表的優勢就很明顯,但鏈表也喪失了隨機訪問的能力,所以對於大數據量的頻繁查詢操作使用順序存儲結構比較好。
C語言代碼:
1.LinkedList.c

typedef int ElemType;
typedef int Status;

#include <stdlib.h>
#include <stdio.h>

#define ERROR 0
#define OK 1
#define TRUE 1
#define FALSE 0

/**
* 線性表的單鏈表存儲結構
*/
typedef struct Node{
    ElemType data; //數據域
    struct Node *next; //指針域
}Node,*LinkedList;

/**
* 創建帶頭結點的單鏈表
* 使用頭插法:始終將新節點插入到表頭
* @param L
*/
void CreateListHead(LinkedList *L){
    LinkedList p;
    *L =(LinkedList) malloc(sizeof(Node));
    (*L)->next = NULL;  //建立一個帶頭結點的單鏈表
    for (int i = 0; i < 10; ++i) {
        p =(LinkedList) malloc(sizeof(Node)); //生成新的節點
        p->data = i;
        p->next = (*L)->next;
        (*L)->next = p;  //插入到表頭
    }
}

/**
* 創建帶頭結點的單鏈表
* 使用尾插法:始終將新節點插入到表尾
* @param L
*/
void CreateListTail(LinkedList *L){
    LinkedList p,r;
    int i;
    *L =(LinkedList) malloc(sizeof(Node));
    r = *L;  //r爲指向尾部的節點
    for (int i = 0; i < 10; ++i) {
        p =(LinkedList) malloc(sizeof(Node));
        p->data = i;
        r->next = p;  //將線性表表尾的節點指向新的節點
        r = p;  //將新插入的節點定義爲表尾節點
    }
    r->next = NULL;  //當前鏈表結束,最後一個節點的指針置爲空
}

/**
* 遍歷打印鏈表元素
* @param L
*/
void Display(LinkedList L){
    LinkedList p = L->next;  //將第一個節點賦值給臨時節點p
    printf("鏈表的元素爲:");
    if(!p)
        printf("鏈表爲空");
    while (p){
        printf("%d ",p->data);
        p = p->next;
    }
    printf("\n");
}

/**
* 獲取鏈表的長度
* @param L
* @return
*/
int GetLinkedListSize(LinkedList L){
    int len = 0;
    LinkedList p = L->next;
    while (p){
        len++;
        p = p->next;
    }
    return len;
}

/**
* 判斷鏈表是否爲空
* @param L
* @return
*/
int IsLinkedListEmpty(LinkedList L){
    LinkedList p = L->next;
    if(!p)
        return TRUE;
    return FALSE;
}

/**
* 查詢單鏈表,並用e返回L中第i個位置元素的值
* @param L
* @param i
* @param e
* @return
*/
Status GetElement(LinkedList L,int i,ElemType *e){
    int j;
    LinkedList  p;
    p = L->next; //p指向鏈表的第一個節點
    j = 1;
    while (p && j<i){
        p = p->next;
        j++;
    }
    if(!p || j>i)
        return ERROR; //第i個節點不存在
    *e = p->data;
    return OK;
}

/**
* 給單鏈表插入元素,在L中第I個元素之前插入新的元素e
* @param L
* @param i
* @param e
* @return
*/
Status LinkedListInsert(LinkedList *L,int i,ElemType e){
    int j;
    LinkedList p,s;
    p = *L;
    j = 1;
    while (p && j<i){  //找到第i-1個節點
        p = p->next;
        j++;
    }
    if(!p || j>i)
        return ERROR; //第i個節點不存在
    s =(LinkedList) malloc(sizeof(Node));
    s->data = e;
    s->next = p->next;
    p->next = s;
    return OK;
}

/**
* 刪除單鏈表L的第i個節點,並用e返回其值
* @param L
* @param i
* @param e
* @return
*/
Status LinkedListDelete(LinkedList *L,int i,ElemType *e){
    int j;
    LinkedList p,q;
    p = *L;
    j = 1;
    while (p->next && j<i){  //找到第i-1個節點
        p = p->next;
        j++;
    }
    if(!(p->next) || j>i)
        return ERROR;   //第i個節點不存在
    q = p->next;
    p->next = q->next;
    *e = q->data;
    free(q);  //讓系統回收此節點,釋放內存
    return OK;
}

/**
* 刪除整個鏈表
* @param L
* @return
*/
Status ClearLinkedList(LinkedList *L){
    LinkedList p,q;
    p = (*L)->next; //p指向第一個節點
    while (p){
        q = p->next;
        free(p);
        p = q;
    }
    (*L)->next = NULL; //將頭結點的指針域置爲空
    return OK;
}

2.LinkedList.h

typedef int ElemType;
typedef int Status;

#include <stdlib.h>
#include <stdio.h>

#define ERROR 0
#define OK 1
#define TRUE 1
#define FALSE 0

/**
* 線性表的單鏈表存儲結構
*/
typedef struct Node{
    ElemType data; //數據域
    struct Node *next; //指針域
}Node,*LinkedList;

//創建帶頭結點的單鏈表(頭插法)
void CreateListHead(LinkedList *L);

//創建帶頭結點的單鏈表(尾插法)
void CreateListTail(LinkedList *L);

//遍歷打印鏈表元素
void Display(LinkedList L);

//獲取鏈表長度
int GetLinkedListSize(LinkedList L);

//判斷鏈表是否爲空
int IsLinkedListEmpty(LinkedList L);

// 查詢單鏈表,並用e返回L中第i個位置元素的值
Status GetElement(LinkedList L,int i,ElemType *e);

//給單鏈表插入元素,在L中第I個元素之前插入新的元素e
Status LinkedListInsert(LinkedList *L,int i,ElemType e);

//刪除單鏈表L的第i個節點,並用e返回其值
Status LinkedListDelete(LinkedList *L,int i,ElemType *e);

//刪除整個鏈表
Status ClearLinkedList(LinkedList *L);

3.main.c

//初始化一個具有10個元素的鏈表(頭插法)
LinkedList list;
CreateListHead(&list);
Display(list);
//初始化一個具有10個元素的鏈表(尾插法)
CreateListTail(&list);
Display(list);
//獲取鏈表長度
int len = GetLinkedListSize(list);
printf("%d",len);
printf("\n");
//判斷鏈表是否爲空
int result = IsLinkedListEmpty(list);
printf("%d",result);
printf("\n");
//查詢鏈表某個位置的元素
int num;
int *n = &num;
GetElement(list,6,n);
printf("%d",*n);
printf("\n");
//插入元素
LinkedListInsert(&list,3,16);
Display(list);
//刪除元素
int delNum;
int *d = &delNum;
LinkedListDelete(&list,3,d);
Display(list);
printf("%d",*d);
printf("\n");
//刪除整個鏈表
ClearLinkedList(&list);
Display(list);
int result2 = IsLinkedListEmpty(list);
printf("%d",result2);

4.執行結果

鏈表的元素爲:9 8 7 6 5 4 3 2 1 0
鏈表的元素爲:0 1 2 3 4 5 6 7 8 9
10
0
5
鏈表的元素爲:0 1 16 2 3 4 5 6 7 8 9
鏈表的元素爲:0 1 2 3 4 5 6 7 8 9
16
鏈表的元素爲:鏈表爲空
1

java代碼:

public class LinkedList<E> {

    private class Node{
        public E e;
        public Node next;

        public Node(E e,Node next){
            this.e = e;
            this.next = next;
        }

        public Node(E e){
            this(e,null);
        }

        public Node(){
            this(null,null);
        }

        @Override
        public String toString() {
            return e.toString();
        }
    }

    private Node dummyHead; //鏈表頭結點
    private  int size;

    public LinkedList(){
        this.dummyHead = new Node(null,null);
        this.size= 0;
    }
    //獲取鏈表中元素的個數
    public int getSize(){
        return size;
    }

    //鏈表是否爲空
    public boolean isEmpty(){
        return size == 0;
    }

    //在鏈表指定的位置添加元素
    public void  add(int index,E e){  //鏈表實際上是沒有索引的概念的,爲了便於理解起見,這裏引入索引概念,這裏索引從0開始,和C語言版的鏈表區分
        if(index < 0 || index > size){
            throw  new IllegalArgumentException("非法索引");
        }
        Node prev = dummyHead;
        for (int i = 0; i < index ; i++) {
            prev = prev.next;
        }
       /* Node node = new Node(e);
        node.next = prev.next;
        prev.next = node;*/
        prev.next = new Node(e,prev.next);  //此處的代碼執行效果等價於上面註釋掉的代碼
        size++;
    }

    //在鏈表頭添加新的元素
    public void addFirst(E e){
        //1
       /* Node node = new Node(e); //1和2的執行效果等價
        node.next = head;100
        head = node;
        */
       // 2 head = new Node(e,head);
       add(0,e);
    }

    //在鏈表的末尾添加新的元素
    public void  addLast(E e){
        add(size,e);
    }

    //獲取鏈表指定位置元素
    public E get(int index){
        if(index < 0 || index >= size){
            throw  new IllegalArgumentException("非法索引");
        }
        Node cur = dummyHead.next;
        for (int i = 0; i < index ; i++) {
            cur = cur.next;
        }
        return cur.e;
    }

    //獲取鏈表的第一個元素
    public E getFirst(){
        return get(0);
    }

    //獲取鏈表的最後一個元素
    public E getLast(){
        return get(size-1);
    }

    //修改鏈表指定位置的元素值
    public void set(int index,E e){
        if(index < 0 || index >= size){
            throw  new IllegalArgumentException("非法索引");
        }
        Node cur = dummyHead.next;
        for (int i = 0; i < index ; i++) {
            cur = cur.next;
        }
        cur.e = e;
    }

    //查找鏈表是否有元素e
    public boolean contains(E e){
        Node cur = dummyHead.next;
        while (cur != null){
            if(cur.e.equals(e)){
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

    //刪除指定位置的鏈表元素
    public E remove(int index){
        if(index < 0 || index >= size){
            throw  new IllegalArgumentException("非法索引");
        }
        Node prev = dummyHead;
        for (int i = 0; i < index; i++) {  //找到要刪除節點的前一個節點
            prev = prev.next;
        }
        Node retNode = prev.next;
        prev.next = prev.next.next;
        retNode.next = null;
        size--;
        return retNode.e;
    }

    //刪除鏈表的第一個元素
    public E removeFirst(){
        return remove(0);
    }

    //刪除鏈表的最後一個元素
    public E removeLast(){
        return remove(size-1);
    }

    @Override
    public String toString() {
        StringBuilder res = new StringBuilder();
        Node cur = dummyHead.next;
        while (cur != null){
            res.append(cur + "->");
            cur = cur.next;
        }
        res.append("NULL");
        return res.toString();
    }

    public static void main(String[] args) {
        LinkedList<Integer> linkedList = new LinkedList<>();
        for (int i = 0; i < 5; i++) {
            linkedList.addFirst(i);
            System.out.println(linkedList);
        }
        linkedList.add(0,521);
        System.out.println(linkedList);
        linkedList.add(3,521);
        System.out.println(linkedList);
        int num = linkedList.get(2);
        System.out.println(num);
        linkedList.remove(3);
        System.out.println(linkedList);
        linkedList.removeFirst();
        System.out.println(linkedList);
    }
}

微信公衆號:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章