数据结构—链表

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

  • 相比于顺序表,其具有如下优点:
    • 线性链表无需实现定义链表最大长度,只要存储空间充足,就可以增加链表结点,不存在溢出问题。
    • 线性链表插入和删除操作简单,只需要修改链接指针,无需大量元素移动,时间复杂度为O(1)。

现在准备找工作了,于是打算复习一下以前学过的,大学三年里一直都没怎么认真过,现在我有点慌了,于是打算写篇博客来记录一下,算是补补旧账。当然如果能给有需要的人帮助那就最好了。就个人感觉,顺序表和线性链表是数据结构中最简单的两个了,但很重要。

链表结点类、链表类的声明:

class listNode//链表结点
    {
    public:
        int element;
        listNode *next;
        //构造函数
        listNode() {}
        listNode(int ele, listNode *l) 
        {
            element = ele;
            next = l;
        }
    };
    class listArray//链表类
    {   
        listNode* head;//头结点指针
    public: 
        //构造、析构函数
        listArray() {}
        listArray(listNode *h)
        {
            head = h;
        }
        ~listArray()
        {
            delete head;
        }
        void creat(int num);//创建num个结点的链表
        void insert(listNode* node,int pos);//把一个结点插入到pos位置
        void del();//删除所有节点
        void trans();//转置
        void dis();//正序打印
        void delByItem(int val);//按值删除结点
        void disDes(listNode* h);//倒序打印

        int length();//链表长度

        listNode* getHead();//返回链表头结点
    };

链表的创建:

首先new一个链表的头结点,给其赋初值,再把head指向头结点;这里声明了一个指向新生成结点前一个的指针temp,在生成后续结点循环内,每new一个结点对象,就把temp->next指向新生成的结点对象,在把temp指向新生成的结点对象。

void listArray::creat(int num)
    {
        if (num > 0)
        {
            listNode* firstNode = new listNode(1,NULL);
            listNode* temp = firstNode;
            head = firstNode;
            for (int i = 1;i < num;i++)
            {
                listNode* newNode = new listNode(i+1,NULL);
                temp->next = newNode;
                temp = newNode;
            }
        }
    }

链表的插入:

链表插入的位置有三种:头结点之前,链表结点中、链表末尾。我这里pos=0表示头结点前,pos=n(n<=链表长度)表示第n个结点后插入。



void listArray::insert(listNode* node,int pos)
    {
        int length = this->length();
        if (pos == 0)
        {
            node->next = head;
            this->head = node;
        }
        else if (pos > 0 && pos <= length)
        {
            listNode* t = head;
            for (int i = 1;i < pos;i++)
            {
                t = t->next;
            }
            node->next = t->next;
            t->next = node;
        }
        else
        {
            cout << "插入位置无效。" << endl;
        }
    }

链表的打印:

在while循环内打印链表。首先用一个结点指针t来遍历所有结点,只要t不为NULL就打印结点。

void listArray::dis()
    {
        listNode* t = head;
        if (head !=NULL)
        {
            while (t != NULL)
            {
                if (t->next != NULL)
                    cout << t->element << "->";
                else
                    cout << t->element << endl;
                t = t->next;
            }
        }
        else
            cout << "空链表。" << endl;
    }

链表的转置:

链表转置需要记录三个位置结点的指针,由于head也需要变动,所以只用额外声明两个结点指针p、q(好久没写代码了,当时想了好久才明白T-T)。



void listArray::trans()
{
    listNode* p = NULL, *q = head;
    while (head!=NULL)
    {
        q = q->next;
        head->next = p;
        p = head;
        head = q;
    }
    head = p;
}

链表的倒序输出:

相信很多人看到这个第一时间想到的就是用栈了吧。。毕竟栈的最大特性就是先进后出。不过在百度一番后还有很多实现方法,这里我选了递归(讲道理学了这么久,这递归还真是没学明白个所以然。递归最经典的问题就是阶乘了,想必大家都很熟悉了。我对递归理解是:问题的求解需要下一个问题的答案,这让不断调用自身,直至递归到边界,然后一层层返回求出结果。我感觉我的理解没问题,实可际就是不会用,这就很尴尬了。递归最大的好处就是代码简洁明了,还需要补补啊!)

void listArray::disDes(listNode* h)
    {
        if (h != NULL)
        {
            if (h->next != NULL)
            {
                disDes(h->next);
            }
            if (h != head)
                cout << h->element << "->";
            else
                cout << h->element;
        }
    }

链表删除指定值结点:

最直接的想法就是遍历所有结点,找出要删除的结点,记录它的前一个结点,然后就把前一个结点的next指针指向所要删除结点的后一个结点。然后在寻找下一个,以此类推。下面是我自己写的代码,很长。。。

void listArray::delByItem(int val)
    {
        listNode* t = head,*p=head;
        while (t)
        {
            if (t->element == val)
            {
                if (p == t)//当删除的结点为头结点时
                {
                    head = head->next;
                    delete(p);
                    p = head;
                    t = head;
                }
                else
                {
                    p->next = t->next;
                    delete(t);
                    t = p->next;
                }
            }
            else
            {
                p = t;
                t = t->next;
            }
        }
    }

这个是人家写的。。。c++STL库中list容器的删除对应值结点的实现:

void List::removeData(int data)  
    {  
       for(Node** cur = &m_head;*cur;)  
       {  
         Node* entry = *cur;  
         if(entry->data == data)  
         {  
            *cur=entry->next;  
            free(entry);  
         }  
         else  
             cur=&entry->next;  
       }  
    }

链表的删除:

与前面的打印类似,遍历链表所有结点,然后删除。

    void listArray::del()
    {
        listNode* t = head;
        while (head != NULL)
        {
            t = t->next;
            delete(head);
            head = t;
        }                                                                                                                                                                                                                                                                                                                                            
    }  

测试代码下载:
http://download.csdn.net/detail/tq1996/9763490

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值