数据结构基础之单链表

数据结构基础之单链表node

对单链表的创建,插入,删除,逆序,打印元素作一个小小的总结,不过我不以为这些东西在具体的工做后到底能发挥什么做用,由于强大的STL已经把这些都作好了,咱们只须要明白在什么场合使用哪个STL就能够了。链表有一个数据域,有一个指针域,它的操做其实就是对指针域的操做,无非是指来指去而已。也许这些能反映出一我的的思惟敏捷度,以及扎实的编程基础吧。ios

可是我想说的是这些玩意在你头脑比较清楚的时候写这个很简单,可是当你烦躁的时候,很差写吧,除非你常常写这个。单链表看着简单,可是不见得能写的正确。编程

该代码通过验证,测试正确,可是代码中难免有错误之处,或者哪些部分写的很差,但愿高手能指出来,不胜感激。由于代码必须通过验证,那些没有通过验证的代码是不负责任的代码。在代码中我加了详细的注释。数据结构

#include <stdio.h>
#include <string>
#include <iostream>

using namespace std;

typedef struct NODE_STRU
{
    int data;//数据域
    struct NODE_STRU *next;//指针域
}NODE;

//建立单链表
NODE *Create()
{
    NODE *head, *p, *s;//head表示头结点,p表示当前节点,s表示添加的新节点
    int input_data;
    int cycle_flag = 1;
    head = (NODE*)malloc(sizeof(NODE));//首先为头结点分配空间
    p = head;//当前节点指向头结点

    while(cycle_flag)
    {
        cout << "please input data(if input 0, cycle over!):"<< endl;
        cin >> input_data;
        if(0 != input_data)
        {
            s = (NODE*)malloc(sizeof(NODE));//为新添加的数据分配节点空间
            s->data = input_data;
            p->next = s;//当前节点的下一个节点指向新节点
            p = s;//将当前节点指向新节点
        }
        else
        {
            cycle_flag = 0;
        }
    }

    head = head->next;//因为头结点没有数据,使头结点指向下一个节点,即指向第一个真正的节点
    p->next = NULL;//数据插入完成后,当前节点也跑到了最后,使它的下一个节点置为NULL,表示节点完成

    return head;
}

//单链表测长,这个很简单,只需判断当前节点(初始化当前节点为头结点)是否是为空,若是不为空指向下一个节点,并计数就能够了
int Length(NODE *head)
{
    int length = 0;
    NODE *p = head;
    while(p != NULL)
    {
        p = p->next;
        length++;
    }
    return length;
}

//打印单链表,这个也很简单,在当前节点(初始化当前节点为头结点)不为空时候,打印出来,并使得当前节点指向下一个节点便可
void Print(NODE *head)
{
    NODE *p = head;
    int length = Length(head);
    cout << "link length is: " << length << endl;
    while(p != NULL)
    {
        cout << "data: " << p->data << "\t";
        p = p->next;
    }

}

//删除节点,这里的删除节点是根据节点数据进行删除的,不是从第一个节点进行删除,也不是从最后一个节点进行删除
//p->next = p->next->next
NODE *Del(NODE *head, int num)
{
    NODE *p1, *p2;//p1表示当前节点,初始化时指向头结点
    p1 = head;

    while(num != p1->data && p1->next != NULL)//若是当前节点的数据域与要删除的数据不相等,使当前节点指向下一个节点
    {
        p2 = p1;//在未找到节点时指针指向下一个节点前,先保存该节点
        p1 = p1->next;
    }

    if(num == p1->data)//若是当前节点数据域与要删除的数据相等
    {
        if(p1 == head)//若是当前节点为头结点,将头结点指向当前节点的下一个节点,并释放当前节点
        {
            head = p1->next;
            free(p1);
        }
        else//若是当前节点为中间节点,使当前节点指向下一个节点,注意:这里不能使用p1->next=p1->next->next,使用以前保存的节点
            p2->next = p1->next;
    }
    else
        cout << num << "can not find in link!" << endl;

    return head;
}

//插入节点,在这里只在链表的结尾进行插入
NODE *Insert(NODE *head, int num)
{
    NODE *p0, *p1, *p2;//p0表示新插入的节点,p1表示当前节点,初始化的时候指向头结点,p2用于保存当前节点
    p1 = head;
    p0 = (NODE *)malloc(sizeof(NODE));
    p0->data = num;

    while(p1->next != NULL)//若是当前节点的下一个节点不为空,当前节点指向下一个节点,这样当前节点最后为最后一个节点
    {
        p2 = p1;
        p1 = p1->next;
    }
    p1->next = p0;
    p0->next = NULL;

    return head;
}

//进行排序,其实就是简单的冒泡排序,时间复杂度为O(n2),空间复杂度为O(1),稳定
NODE *Sort(NODE *head)
{
    NODE *p;
    if(head == NULL || head->next == NULL)
        return head;

    int length = Length(head);//获得链表的长度,用于遍历
    for(int i=1; i<length; i++)
    {
        p = head;
        for(int j=0; j<length-i; j++)
        {
            if(p->data > p->next->data)
            {
                int temp = p->data;
                p->data = p->next->data;
                p->next->data = temp;
            }
            p = p->next;
        }
    }

    return head;
}

//链表逆序
NODE *Reverse(NODE *head)
{
    if(head == NULL || head->next == NULL)
        return head;
    //这样来实现,在链表中一次从链表尾删除节点,而后在新创建的链表中插入节点(尾插法)
    int length = Length(head);
    int a[length];
    int i = 0;
    NODE *p = head;
    while(p != NULL)
    {
        a[i] = p->data;
        i++;
        p = p->next;
    }

    for(int j=0; j<length; j++)//暂时用于测试
        cout << j << ":" << a[j]<<"\n";

    NODE *newhead, *link, *s;
    newhead = (NODE *)malloc(sizeof(NODE));
    link = newhead;
    for(int k=length-1; k>=0; k--)
    {
         s = (NODE *)malloc(sizeof(NODE));
         s->data = a[k];
         link->next = s;
         link = s;
    }
    newhead = newhead->next;
    link->next = NULL;

    return newhead;
}

//求单链表的中间节点
void SearchMid(NODE* head)
{
    cout << "head data: " << head->data<< "\n";
    NODE *tmp1 = head;
    NODE *tmp2 = head;
    NODE *mid;
    while(tmp1->next != NULL && tmp1->next->next != NULL)
    {
        tmp1 = tmp1->next->next;
        tmp2 = tmp2->next;
        cout << "tmp1:" << tmp1->data<< ",tmp2:" << tmp2->data<<"\n";
    }
    mid = tmp2;
    cout << "SearchMid mid data: " << mid->data;
}

int main(int argc, char *argv[])
{
    cout << "create link...\n" << endl;
    NODE *p = Create();
    cout << "print link...\n" << endl;
    Print(p);

    int delnode;
    cout << "\ninput delete node: ";
    cin >> delnode;
    cout << "\ndelete node " << delnode << endl;
    Del(p, delnode);
    cout << "print link..." << endl;
    Print(p);

    cout << "\ninsert link...\n";
    Insert(p, 20);
    Print(p);

    cout <<"\nsort from low to high...";
    Sort(p);
    Print(p);

    cout << "\nreverse...\n";
    NODE *revlink = Reverse(p);
    Print(revlink);

    cout << "\nfind mid node data...\n";
    SearchMid(p);

    return 0;
}

运行结果:测试


如是转载,请指明原出处:http://blog.csdn.net/feitianxuxue,谢谢合做!
spa