学习数据结构——线性表与链表

线性表是一种最基本的数据结构,通常可以分为顺序表和链表。
顺序表即数据的存储空间是连续的,而链表的前后元素需要靠指针来连接。
顺序表简单,但是通常存在着

  • 插入删除操作时需要移动大量数据,效率极低;
  • 最大表长度难以估计,太大了浪费空间,太小了容易溢出。

但是链表的性质却可以很好的解决以上两个问题。以下是两个链表的示例程序。一个静态,一个动态,均有较详细的注释,以备日后回顾复习。

注意,在Visual Studio的高版本(一般高于VS2013)中运行两个程序时,`scanf()`函数会报错,或者出现这样的问题:
error C4703: 使用了可能未初始化的本地指针变量“xxx”
这时可以打开 项目属性->配置属性->C/C++->SDL检查,选择SDL检查为“否”,即可解决问题。

静态链表示例程序

用数组模拟静态的链表,长度预先定义好,不能动态分配内存。

//简单静态链表

#include <iostream>
using namespace std;

struct student
{
    long num;
    float score;
    struct student * next;  //指向该类结构体
};  //注意分号

int main()
{
    struct student a,b,c,* head,* p;
    a.num = 0001;
    a.score = 99;
    b.num = 0002;
    b.score = 98;
    c.num = 0003;
    c.score = 97;

    head = &a;     //头指针 
    a.next = &b;
    b.next = &c;
    c.next = NULL;  //尾指针 

    p = head;   //迭代的时候不能用头指针本身去迭代,否则就乱了 
    do
    {
        cout << p->num << " " << p->score << endl;
        p = p->next;
    }while( p != NULL );

    getchar();   //输出结果后起到暂停作用 

}

动态链表示例程序,包含链表常用的若干种操作

用指针实现动态链表,malloc函数和free函数可以实现内存的动态分配。具有较大灵活性。

注意在C++语言中使用printf()函数要引入标准输入输出库。C语言中使用#include <stdio.h>,而C++语言中使用#include <cstdio>来实现。

//动态链表程序
#include "stdafx.h"
#include <cstdio>
#include <iostream>
#include <cstdlib>

using namespace std;
using namespace std;
typedef int ElemType;
typedef struct List * link;
typedef struct List Lnode;

struct List    //定义链表
{
    ElemType data;
    struct List * next;
};

link setnull(link Head)   //置空链表,输入一个链表的头指针
{
    link p;
    p = Head;    //头指针赋给指针p
    while (p != NULL)
    {
        p = p->next;    //p指向链表的下一个元素
        free(Head);    //把p指针的上一个指针(Head)所占空间释放
        Head = p;    //p所指的结点(node)成为新的Head
    }

    return Head;
}

link insert(link Head, ElemType x, int i)  // Head是已知链表,x是要插入的数,i是插入位置
{
    link NewPoint, p = Head;
    int j = 1;
    NewPoint = (link)malloc(sizeof(Lnode));  //生成一个link类型的,长度为一个节点的内存空间
    NewPoint->data = x;
    if (i == 1)  //如果插入位置是第一个,直接令NewPoint为头指针,NewPoint的next指向原第一个结点
    {
        NewPoint->next = Head;
        Head = NewPoint;
    }
    else
    {
        while (j<i - 1 && p->next != NULL) //把p指针从头移到要插入的前一位
        {
            p = p->next;
            j++;  //此时j应该等于i-1
        }
        if (j == i - 1)  //把NewPoint插进去
        {
            NewPoint->next = p->next;
            p->next = NewPoint;
        }
        else  //超过范围就报错
        {
            printf("insert is failure,i is not right!");
        }
    }
    return Head;  //最后返回更改后的链表指针
}

link create(link Head) //生成链表
{
    ElemType newData;  //新数据
    link NewPoint;  //新指针

    Head = (link)malloc(sizeof(Lnode));  //给头指针分配一个节点大小的内存空间
    printf("please input number: \n");
    printf("caution! 倒序输入 \n");
    scanf("%d", &newData);
    printf("you type %d as the last number\n", newData);
    //cin >> newData;
    Head->data = newData;
    Head->next = NULL;  //头指针的后面暂无结点

    while (1)
    {
        NewPoint = (link)malloc(sizeof(Lnode));  //产生新节点
        if (NewPoint == NULL)  //如果分配内存失败,跳出while
        {
            break;
        }
        printf("please input number : input '-1' means exit\n");
        scanf("%d", &newData);
        //cin >> newData;
        if (newData == -1) //结束标志
        {
            return Head;
        }
        NewPoint->data = newData;  //把NewPoint接在Head前面
        NewPoint->next = Head;
        Head = NewPoint;
    }
    return Head;
}

int length(link Head)  // 计算一个链表的长度
{
    int len = 0;
    link p;   //不要直接操作Head,会改乱指针
    p = Head;
    while (p != NULL)  //只要p不是空指针,就计数
    {
        len++;
        p = p->next;
    }
    return len;
}

ElemType get(link Head, int i)  // 返回Head链表的i位置的数据
{
    int j = 1;
    link p;
    p = Head;
    while (j<i && p != NULL)
    {
        p = p->next;
        j++;
    }
    if (p != NULL)
    {
        return (p->data);
    }
    else//这种情况出现在给定的i超过了链表的长度
    {
        //printf("data is error!");
        cout << "data is error!";
    }
    return -1;
}

int locate(link Head, ElemType x)  //在给定链表中确定数据x的位置
{
    int n = 0;
    link p;
    p = Head;
    while (p != NULL && p->data != x)  //一直找,找到x前一个停下
    {
        p = p->next;
        n++;
    }
    if (p == NULL) //如果Head链表里没有这个数据,p会最终指到NULL上
    {
        return -1;
    }
    else
    {
        return n + 1;
    }
}

void display(link Head)  //在屏幕上打印链表
{
    link p;
    p = Head;
    if (p == NULL)
    {
        //printf("\nList is empty");
        cout << "\nList is empty";
    }
    else
    {
        do
        {
            printf("%d", p->data);
            p = p->next;
        } while (p != NULL);
    }
    cout << endl;
}

link connect(link Head1, link Head2)  //将两个链表连接起来,Head1在前,Head2在后
{
    link p;
    p = Head1;
    while (p->next != NULL)  //p指针一直指到Head1链表的最后一个结点处
    {
        p = p->next;
    }
    p->next = Head2;  //在Head1最后接上Head2链表的第一个结点
    return Head1;
}

link del(link Head, int i)  //删除
{
    int j = 1;
    link p, t;
    p = Head;
    if (i == 1)
    {
        p = p->next;  //如果要删除的是第一个位置的数据,就把p指针指向下一个元素,然后将Head释放
        free(Head);  //释放p所指的空间
        Head = p;  //新的头指针
    }
    else  //如果要删除的元素不在第一个位置
    {
        while (j < i - 1 && p->next != NULL)  //先将p指向要删除的结点的前一个位置,而且要保证要删除的元素没有超出链表的长度
        {
            p = p->next;
            j++;
        }
        if (p->next != NULL && j == i - 1)
        {
            t = p->next;
            p->next = t->next;  //直接跳过第i个结点,将第i-1个结点和第i+1个结点连在一起
        }
        if (t != NULL)
        {
            free(t);  //把中间变量释放掉
        }
    }
    return Head;
}

int compare(link Head1, link Head2)  //比较两个链表是否相同:长度一致,且数据相同
{
    link p1, p2;
    p1 = Head1;
    p2 = Head2;
    while (1)
    {
        if ((p1->next == NULL) && (p2->next == NULL))  //当Head1和Head2同时达到链尾才成立
        {
            return 1;  //两链表相同
        }
        if (p1->data != p2->data)  //比较过程中只要有不一样的数据就返回0
        {
            return 0;
        }
        else
        {
            p1 = p1->next;  //不断迭代
            p2 = p2->next;
        }
    }
}

int main()
{
    int l;
    link head1 = NULL;
    link head2 = NULL;

    printf("\nNow we generate the first linked list\n");
    head1 = create(head1);  //生成第一个链表
    printf("\nHead1 is :\n");  //显示出来
    display(head1);

    printf("\nNow we generate the second linked list\n");
    head2 = create(head2);  //生成第二个链表
    printf("\nHead2 is :\n");  //显示出来
    display(head2);

    printf("\nNow we compare the two linked lists\n");  //比较两个链表是否相同
    l = compare(head1, head2);
    printf("\nl is %d\n", l);

    printf("\nNow we connect two linked lists\n");
    connect(head1, head2);  //将head1与head2接起来
    printf("\nHead1 + Head2 is \n");
    display(head1);

    printf("\nNow we calculate the first linked list\n");
    l = length(head1);  //计算head1的长度
    printf("\nthe length of link1 is %d\n", l);

    l = get(head1, 3);  //获取head1链表第三个元素的值
    printf("\nthe 3th element of link1 is %d\n", l);

    l = locate(head1, 12);  //查找12在链表中的位置,没有则返回1
    printf("\nlocate 12 is %d \n", l);

    printf("\nNow we insert 555 to 8th of the first linked list\n");
    head1 = insert(head1, 555, 8);  //在第8位插入数据555
    display(head1);

    printf("\nNow we delete the 7th element of the first linked list\n");
    head1 = del(head1, 7);  //删除第7个结点
    display(head1);

    printf("\nNow we clear the first linked list\n");
    head1 = setnull(head1);  //将head1置空
    display(head1);

    printf("\nNow wait to exit: press any key and enter\n");
    cin >> l;
    return 0;

}


猜你喜欢

转载自blog.csdn.net/hhy_csdn/article/details/78255911