1. 程式人生 > >python演算法與資料結構-雙向連結串列(40)

python演算法與資料結構-雙向連結串列(40)

一、雙向連結串列的介紹

  一種更復雜的連結串列是“雙向連結串列”或“雙面連結串列”。每個節點有兩個連結:一個指向前一個節點,當此節點為第一個節點時,指向空值;而另一個指向下一個節點,當此節點為最後一個節點時,指向空值。

  

  上圖是雙向連結串列的結構圖,即通過上一個節點可以找到下一個,通過下一個也可以找到上一個節點。

二、雙向連結串列插入和刪除的圖解

  1、插入圖解

  

  2、刪除圖解

  

三、雙向連結串列的python程式碼實現

# 1、建立節點
class Node(object):
    # 初始化方法
    def __init__(self, item):
        self.item= item
        self.next = None
        self.prev = None

# 2、建立迴圈連結串列
class DoubleLinKList(object):
    # 初始化方法
    def __init__(self):
        self._head = None
    
    # 3、判斷是否為空
    def is_empty(self):
        """判斷連結串列是否為空"""
        return self._head == None
    
    # 4、求其長度
    def length(self):
        """返回連結串列的長度"""
        cur = self._head
        count = 0
        while cur != None:
            count += 1
            cur = cur.next
        return count
    
    # 遍歷
    def travel(self):
        """遍歷連結串列"""
        print("你要遍歷的連結串列元素有:",end=" ")
        cur = self._head
        while cur != None:
            print("%s "%cur.item,end=" ")
            cur = cur.next
        print("")
    
    # 5、頭插
    def add(self, item):
        """頭部插入元素"""
        node = Node(item)
        if self.is_empty():
            # 如果是空連結串列,將_head指向node
            self._head = node
        else:
            # 將node的next指向_head的頭節點
            node.next = self._head
            # 將_head的頭節點的prev指向node
            self._head.prev = node
            # 將_head 指向node
            self._head = node
    
    # 6、尾插
    def append(self, item):
        """尾部插入元素"""
        node = Node(item)
        if self.is_empty():
            # 如果是空連結串列,將_head指向node
            self._head = node
        else:
            # 移動到連結串列尾部
            cur = self._head
            while cur.next != None:
                cur = cur.next
            # 將尾節點cur的next指向node
            cur.next = node
            # 將node的prev指向cur
            node.prev = cur
    
    # 7、查詢
    def search(self, item):
        """查詢元素是否存在"""
        cur = self._head
        while cur != None:
            if cur.item == item:
                return True
            cur = cur.next
        return False
    
    # 8、指定位置插入
    def insert(self, pos, item):
        """在指定位置新增節點"""
        if pos <= 0 or pos>self.length()+1 :
            print("你輸入的位置有誤,請重新輸入")
        elif pos == 1:
            self.add(item)
        elif pos == self.length()+1:
            self.append(item)
        else:
            node = Node(item)
            cur = self._head
            count = 1
            # 移動到指定位置的前一個位置
            while count < (pos - 1):
                count += 1
                cur = cur.next
            # 將node的prev指向cur
            node.prev = cur
            # 將node的next指向cur的下一個節點
            node.next = cur.next
            # 將cur的下一個節點的prev指向node
            cur.next.prev = node
            # 將cur的next指向node
            cur.next = node
    
    # 9、刪除
    def remove(self, item):
        """刪除元素"""
        if self.is_empty():
            return
        else:
            cur = self._head
            if cur.item == item:
                # 如果首節點的元素即是要刪除的元素
                if cur.next == None:
                    # 如果連結串列只有這一個節點
                    self._head = None
                else:
                    # 將第二個節點的prev設定為None
                    cur.next.prev = None
                    # 將_head指向第二個節點
                    self._head = cur.next
                return
            while cur != None:
                if cur.item == item:
                    # 將cur的前一個節點的next指向cur的後一個節點
                    cur.prev.next = cur.next
                    # 將cur的後一個節點的prev指向cur的前一個節點
                    cur.next.prev = cur.prev
                    break
                cur = cur.next

# 驗證
if __name__ == '__main__':
    
    double_link = DoubleLinKList()
    # 頭插
    double_link.add(1)
    # 遍歷
    double_link.travel()
    # 尾插
    double_link.append(2)
    double_link.travel()
    # 按照索引插入
    double_link.insert(3,4)
    double_link.travel()
    
    double_link.insert(3,3)
    double_link.travel()
    # 刪除
    double_link.remove(3)
    double_link.travel()

執行結果為:

你要遍歷的連結串列元素有: 1  
你要遍歷的連結串列元素有: 1  2  
你要遍歷的連結串列元素有: 1  2  4  
你要遍歷的連結串列元素有: 1  2  3  4  
你要遍歷的連結串列元素有: 1  2  4 

四、雙向連結串列的C語言程式碼實現

//  main.m
//  雙向連結串列
//  Created by 侯壘 on 2019/6/28.
//  Copyright © 2019 可愛的侯老師. All rights reserved.

#import <Foundation/Foundation.h>
typedef struct N
{
    int element;
    struct N *next;
    struct N *prev;
}Node;

// 建立節點
Node *createNode(int num)
{
    Node *node = (Node *)malloc(sizeof(Node));
    node->element = num;
    node->next = NULL;
    node->prev = NULL;
    return node;
}

// 建立雙向連結串列
Node *createDoubleLinkList(Node *node)
{
    Node *head = node;
    return head;
}

// 判斷是否為空
int is_empty(Node *head)
{
    if (head == NULL)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

// 求其長度
int length(Node *head)
{
    Node *current = head;
    int count = 0;
    while (current != NULL)
    {
        count++;
        current = current->next;
    }
    return count;
}

// 遍歷
void travel(Node *head)
{
    printf("你要遍歷的資料有:");
    Node *current = head;
    while (current != NULL)
    {
        printf("%d ",current->element);
        current = current->next;
    }
    printf("\n");
}

// 頭插
Node * add(Node *head,int num)
{
    Node *node = createNode(num);
    if (is_empty(head)==1)
    {
        head = node;
    }
    else
    {
        node->next = head;
        head->prev = node;
        head = node;
    }
    return head;
}

// 尾插
Node* append(Node *head,int num)
{
    Node *node = createNode(num);
    if (is_empty(head)==1)
    {
        head = node;
    }
    else
    {
        Node *current = head;
        while (current->next != NULL)
        {
            current = current->next;
        }
        current->next = node;
        node->prev = current;
    }
    return head;
}

// 查詢
int search(Node *head,int num)
{
    Node *current = head;
    for (int i=0; i<length(head); i++)
    {
        if (current->element == num)
        {
            return i+1;
        }
        current = current->next;
    }
    return 0;
}

// 按指定位置插入
Node * insert(Node *head ,int index,int num)
{
    if (index<=0||index>length(head)+1)
    {
        printf("你要插入的位置不對,請重新插入");
    }
    else if (index == 1)
    {
       head = add(head, num);
    }
    else if (index == length(head)+1)
    {
        append(head, num);
    }
    else
    {
        Node *node = createNode(num);
        Node *current = head;
        for (int i=1; i<index-1; i++)
        {
            current = current->next;
        }
        node->prev = current;
        node->next = current->next;
        current->next->prev = node;
        current->next = node;
    }
    return head;
}

// 刪除元素
Node * removeNode(Node *head,int num)
{
    if (is_empty(head)==1)
    {
        printf("你要刪除的連結串列為空");
    }
    else
    {
        Node *current = head;
        //處理頭結點就是要刪除的節點
        if (current->element == num)
        {
            if (current->next == NULL)
            {
                // 只有首節點這一個元素
                head = NULL;
            }
            else
            {
                // 要刪除的是首節點,但是後面還有元素
                current->next->prev = NULL;
                head = current->next;
            }
        }
        else
        {
            while (current!=NULL)
            {
                if (current->element == num)
                {
                    current->prev->next = current->next;
                    current->next->prev = current->prev;
                    break;
                }
                current = current->next;
            }
        }
    }
    return head;
}

int main(int argc, const char * argv[]) {
    
    // 建立節點
    Node *node = createNode(1);
    // 建立連結串列
    Node *head = createDoubleLinkList(node);
    // 驗證遍歷
    travel(head);
    // 驗證頭插
    head = add(head, 0);
    travel(head);
    // 驗證尾插
    head = append(head, 3);
    travel(head);
    
    // 驗證查詢
    int index = search(head, 1);
    if (index != 0)
    {
        printf("你要查詢的資料在%d位置\n",index);
    }
    else
    {
        printf("沒有找到你要的資料\n");
    }
    
    //驗證按指定位置插入
    head = insert(head, 2, 2);
    travel(head);
    
    //驗證刪除
    head = removeNode(head, 0);
    travel(head);
    return 0;
}

執行結果為:

你要遍歷的資料有:1 
你要遍歷的資料有:0 1 
你要遍歷的資料有:0 1 3 
你要查詢的資料在2位置
你要遍歷的資料有:0 2 1 3 
你要遍歷的資料有:2 1 3 

&n