循環單鏈表(鏈表)


雙鏈表:插入節點時和刪除節點時注意位置為0的節點。

 

圖:

 

 

繼承關系圖:

 

 

 CircularList.h

/*
*    CirularList: 循環鏈表模板
*    成員變量:
*            
*    成員函數:
*            last_to_first()                        連接首尾節點
*            bool insert(int pos,const T& obj)    插入節點
*            bool remove(int pos)                刪除下標為pos的節點。分三步:頭節點與1節點,尾節點與1節點,刪除0節點
*            bool set(int pos, const T& obj)        
*            bool get(int pos, T& obj) const        
*            int find(const T& obj) const        
*            void clean()                        
*    
*    
*    
*/

#ifndef CIRCULARLIST_H
#define CIRCULARLIST_H

#include"LinkList.h"

namespace DSL
{
    template <typename T>
    class CircularList : public LinkList<T>
    {
        protected:
            typedef typename LinkList<T>::Node Node;
            void last_to_first()
            {
                Node* current = reinterpret_cast<Node*>(&this->m_header);
                for(int i = 0; i < this->m_length; i++)
                {
                    current = current->next;
                }
                current->next = this->m_header.next;
            }

        public:
            bool insert(const T & obj) // 默認插入尾部
            {
                return (this->insert(this->m_length,obj));
            }

            bool insert(int pos, const T & obj)
            {
                bool ret = 1;
                pos = pos % (this->m_length + 1);
                if(pos == 0) // 插入鏈表頭部
                {
                    ret = LinkList<T>::insert(pos,obj);
                    last_to_first();
                }
                else  // 插入鏈表中部
                {
                    ret = LinkList<T>::insert(pos,obj);
                }
                return ret;
            }

            bool remove(int pos)  
            {
                bool ret = 1;
                pos = (this->m_length == 0 ? 0 : (pos % this->m_length));
                if(pos == 0) // 刪除0節點
                {
                    Node* toDel = this->m_header.next;
                    if(this->m_length > 0)  // 節點0存在
                    {
                        this->m_header.next = toDel->next;  
                        this->m_length--;
                        if(this->m_length > 0)  // 刪除0節點后下個節點存在
                        {
                            last_to_first();
                            if(this->m_current == toDel)
                            {
                                this->m_current = toDel->next;
                            }
                        }
                        else
                        {
                            this->m_header.next == NULL;
                            this->m_current = NULL;
                        }
                        this->destroy(toDel);
                    }
                    else
                    {
                        this->m_header.next == NULL;
                        this->m_current = NULL;
                    }
                    
                }
                else // 刪除中間節點
                {
                    ret = LinkList<T>::remove(pos);
                }
                return ret;
            }

            bool set(int pos, const T& obj)
            {
                pos = (this->m_length == 0 ? 0 : (pos % this->m_length));
                return LinkList<T>::set(pos,obj);
            }

            T get(int pos)
            {
                pos = (this->m_length == 0 ? 0 : (pos % this->m_length));
                return LinkList<T>::get(pos);
            }
        
            bool get(int pos, T& obj) const
            {
                pos = (this->m_length == 0 ? 0 : (pos % this->m_length));
                return LinkList<T>::get(pos,obj);
            }

            int find(const T& obj) const
            {
                int ret = -1;
                Node* slider = this->m_header.next;
                for(int i = 0; i < this->m_length; i++)
                {
                    if(slider->value == obj)
                    {
                        ret = i;
                        break;
                    }
                    slider = slider->next;
                }
            }

            void clean()
            {
                for(int i = this->m_length; i > 0; i--)
                {
                    if( this->m_length > 1) // 刪除中間節點
                    {
                        remove(1);
                    }
                    else  // 刪除頭節點
                    {
                        Node* toDel = this->m_header.next;
                        this->m_header.next = NULL;
                        this->m_current = NULL;
                        this->m_length = 0;
                        this->destroy(toDel);
                    }
                }
            }

            bool move(int pos)
            {
                pos = (this->m_length == 0 ? 0 : (pos % this->m_length));
                return LinkList<T>::move(pos);
            }

            bool end()
            {
                return ((this->m_length == 0) || (this->m_current == NULL));
            }

            ~CircularList()
            {
                clean();
            }

    };
}

/*
約瑟夫環
num:   總人數
start: 報數起始位置
step:  報數個數
void Josephus(int num, int start, int step)
{
    CircularList<int> cl;
    for(int i = 1; i <= num; i++)
    {
        cl.insert(i);
    }
    cl.move(start - 1); // 循環鏈表下標從0開始
    while(cl.length() > 0)
    {
        cl.next(step - 1);
        cout << cl.current() << endl;    
        cl.remove(cl.find(cl.current()));
    }
}


*/

#endif
View Code

 

移植Linux內核的鏈表,/include/linux/List.h

LinuxList.h

/*
*    LinuxList.h:    移植Linux4.9的雙向循環鏈表/include/linux/list.h,兼容g++/gcc編譯器。
*    
*    接口函數:
*            list_head:                         鏈表節點,通過內嵌到其他數據結構使用。(頭節點的數據域並未使用)
*
*            INIT_LIST_HEAD:                    初始化鏈表頭,將鏈表頭的next,prev指針都指向自己,此狀態表示鏈表為空
*            list_add:                        鏈表頭節點和第二個節點中間插入
*            list_add_tail:                  鏈表頭節點和尾節點中間插入
*            list_del:                        刪除節點,刪除當前傳入的節點
*            list_empty:                        鏈表是否為空,頭節點的next和prev指針指向自己則為空。
*            list_for_each_entry:            頭節點開始,正向遍歷鏈表
*            list_for_each_entry_reverse:    頭節點開始,逆向遍歷鏈表
*
*            contain_of        通過結構體成員指針,結構體成員名,結構體類型獲取 結構體首地址
*            list_entry        通過父級結構體的內嵌成員list_head的成員指針,成員名,結構體類型獲取 父級結構體的首地址
*/

#ifndef LINUXLIST_H
#define LINUXLIST_H

struct list_head 
{
    struct list_head *next, *prev;
};

#define LIST_HEAD_INIT(name) { &(name), &(name) }

#define LIST_HEAD(name) (struct list_head name = LIST_HEAD_INIT(name))

/*    params: 
*            list_head  頭父級數據結構的鏈表節點
*/
static  void INIT_LIST_HEAD(struct list_head *list)
{
    list->next = list->prev = list;
}

static  void __list_add(struct list_head *entry, struct list_head *prev, struct list_head *next)
{
    next->prev = entry;
    entry->next = next;
    entry->prev = prev;
    prev->next = entry;
}

/*    params: 
*            entry  內嵌到父級數據結構的鏈表節點
*            head   頭父級數據結構中的鏈表節點
*/
static void list_add(struct list_head *entry, struct list_head *head)
{
    __list_add(entry, head, head->next);
}

static void list_add_tail(struct list_head *entry, struct list_head *head)
{
    __list_add(entry, head->prev, head);
}

static void __list_del(struct list_head *prev, struct list_head *next)
{
    next->prev = prev;
    prev->next = next;
}

/*    params: 
*            要刪除父級數據結構中的鏈表頭
*/
static void list_del(struct list_head *entry)
{
    __list_del(entry->prev, entry->next);
}

static void list_del_init(struct list_head *entry)
{
    __list_del(entry->prev, entry->next);
    INIT_LIST_HEAD(entry);
}

static void list_move_tail(struct list_head *list,
                  struct list_head *head)
{
    __list_del(list->prev, list->next);
    list_add_tail(list, head);
}

#ifdef __cplusplus  // C語言沒有bool類型
static bool list_empty(struct list_head *head)
{
    return head->next == head;
}
#else
static int list_empty(struct list_head *head)
{
    return head->next == head;
}
#endif

#ifndef container_of
#define container_of(ptr, type, member) (type *)((char *)(ptr) - (char *)&((type *)0)->member)
#endif

#define list_entry(ptr, type, member)  container_of(ptr, type, member)

#define list_first_entry(ptr, type, member)  list_entry((ptr)->next, type, member)

#define list_last_entry(ptr, type, member)  list_entry((ptr)->prev, type, member)

#ifdef __cplusplus  // C++類型檢查要強一些
#define __container_of(ptr, sample, member)     container_of((ptr), typeof(*(sample)), member)
#else
#define __container_of(ptr, sample, member)     (void *)container_of((ptr), typeof(*(sample)), member)
#endif

/*    params: 
*            pos      用作游標的父級數據結構
*            head    頭父級數據結構的鏈表節點(鏈表頭)
*            member    父級數據結構中定義的list_head的變量名
*/
#define list_for_each_entry(pos, head, member)                \
    for (pos = __container_of((head)->next, pos, member);        \
     &pos->member != (head);                    \
     pos = __container_of(pos->member.next, pos, member))

#define list_for_each_entry_safe(pos, tmp, head, member)        \
    for (pos = __container_of((head)->next, pos, member),        \
     tmp = __container_of(pos->member.next, pos, member);        \
     &pos->member != (head);                    \
     pos = tmp, tmp = __container_of(pos->member.next, tmp, member))

#define list_for_each_entry_reverse(pos, head, member)            \
    for (pos = __container_of((head)->prev, pos, member);        \
         &pos->member != (head);                    \
         pos = __container_of(pos->member.prev, pos, member))

#define list_for_each_entry_continue(pos, head, member)            \
    for (pos = __container_of(pos->member.next, pos, member);    \
         &pos->member != (head);                    \
         pos = __container_of(pos->member.next, pos, member))

#define list_for_each_entry_continue_reverse(pos, head, member)        \
    for (pos = __container_of(pos->member.prev, pos, member);    \
         &pos->member != (head);                    \
         pos = __container_of(pos->member.prev, pos, member))

#define list_for_each_entry_from(pos, head, member)            \
    for (;                                \
         &pos->member != (head);                    \
         pos = __container_of(pos->member.next, pos, member))

#endif

/* TEST

main.cpp:
#include<iostream>
#include"LinuxList.h"
#include<cstdio>

using namespace std;  

int main(void)
{
    struct Node
    {
        int value; 
        struct list_head head;
    };

    Node *m_list = (Node *)malloc(sizeof(Node));
    struct list_head *m_head = &m_list->head;
    Node *m_slider = NULL;   // 游標
    INIT_LIST_HEAD(m_head);

    for(int i=0; i<10; i++)
    {
        Node *temp_node = (Node *)malloc(sizeof(Node));
        temp_node->value = i;
        list_add_tail(&temp_node->head, m_head);
        cout << temp_node->value << endl;
    } 

    list_for_each_entry(m_slider, m_head, head)
    {
        int i = m_slider->value;
        cout << i << endl;
    }
    return 0;
} 

*/
View Code

內核鏈表真的厲害,同一個簡單的代碼包含了所有情況下的插入,刪除,可能這就是真正的代碼復用吧,而不是語法糖。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM