数据结构-单链表-结构体定义

单链表,用于存储逻辑关系为 "一对一" 的数据,与顺序表不同,链表不限制数据的物理存储状态,换句话说,使用链表存储的数据元素,其物理存储位置是随机的。

结点在存储器中的位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻。

例如{1,2,3}:

  

线性表的链式表示又称为非顺序映像或链式映像。

各结点由两个域组成: 

  数据域:存储元素数值数据

  指针域:存储直接后继结点的存储位置  

    

头指针是指向链表中第一个结点的指针

首元结点是指链表中存储第一个数据元素a1的结点

头结点是在链表的首元结点之前附设的一个结点;数据域内只放空表标志和表长等信息

如何表示空表?

答:有头结点时,当头结点的指针域为空时表示空表

在链表中设置头结点有什么好处?

答:⒈便于首元结点的处理

    首元结点的地址保存在头结点的指针域中,所以在链表的第一个位置上的操作和其它位置一致,无须进行特殊处理;

  ⒉便于空表和非空表的统一处理

    无论链表是否为空,头指针都是指向头结点的非空指针,因此空表和非空表的处理也就统一了。

头结点的数据域内装的是什么?

答:头结点的数据域可以为空,也可存放线性表长度等附加信息,但此结点不能计入链表长度值。

链表(链式存储结构)的特点:

1)结点在存储器中的位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻

2)访问时只能通过头指针进入链表,并通过每个结点的指针域向后扫描其余结点,所以寻找第一个结点和最后一个结点所花费的时间不等

这种存取元素的方法被称为顺序存取法

链表的优缺点:

优点:数据元素的个数可以自由扩充

   插入、删除等操作不必移动数据,只需修改链接指针,修改效率较高链表的优缺点

缺点:存储密度小

   存取效率不高,必须采用顺序存取,即存取数据元素时,只能按链表的顺序进行访问(顺藤摸瓜)

单链表是由表头唯一确定,因此单链表可以用头指针的名字来命名

若头指针名是L,则把链表称为表L

用c++描述的单链表大致可以分两种,一种用结构体定义,一种用类定义;

链表也可以分为头插法和尾插法

头插法

生成新结点
将读入数据存放到新结点的数据域中
将该新结点插入到链表的前端

  1 #include<iostream>
  2 using namespace std;
  3 
  4 typedef struct SingLinkList {
  5     int data;                  //数据域
  6     struct SingLinkList *next; //指针域
  7 }SLL,*Slist; //相当于struct SingLinkList,*Slist相当于struct SingLinkList *
  8 
  9 //新建链表,确认链表的长度
 10 void New_LinkList(Slist L,int n)  //Slist L相当于struct SingLinkList * L
 11 {
 12     int i;
 13     int v;
 14     Slist p;
 15     L->next = NULL;      
 16     
 17     //这是用前插法创建链表,此时就不需要使用尾结点了
 18     //所以遍历的结果是与输入值的顺序是相反的
 19     for (int i = n; i > 0; i--)
 20     {
 21         p = (Slist)malloc(sizeof(SLL));
 22         cin >> v;
 23         p->data = v;
 24         p->next = L->next;  //p的指针域指向L的指针域,即p指向空,
 25         L->next = p;        //但是此时只有p这个结点,还需要头结点指向p
 26                             //此时头结点指向p,而p指针域指向最后,
 27                       //可以认为p是尾结点,它的指针域自然要指向空了。
 28          //然后你需要几个结点就继续按照原来的一直干下去。记住这是前插法。
 29         //单链表的结点不像数组可以通过下标找到,它得从头开始找。
 30         //每个节点都与上一个结点相连没有名字是地址传地址
 31     }
 32 }
 33 
 34 // 获取链表中指定位置的数据元素
 35 int GetElem_LinkList( Slist L, int i, int *e)
 36 {
 37     Slist p;
 38     p = L->next;
 39     int j = 1;
 40 
 41     while (p && j < i)
 42     {
 43         p = p->next;
 44         ++j;
 45     }
 46 
 47     if (!p || j > i)
 48     {
 49         return 0;
 50     }
 51 
 52     *e = p->data;
 53     return 1;
 54 }
 55 
 56 // 在链表中指定位置插入数据
 57 int Isert_LinkList(Slist L, int i, int* e)
 58 {
 59     Slist p, s;
 60     p = L;
 61     int j = 0;
 62 
 63     while (p && j < i - 1)
 64     {
 65         p = p->next;
 66         ++j;
 67     }
 68 
 69     if (!p || j > i - 1)
 70     {
 71         return 0;
 72     }
 73 
 74     s = (Slist)malloc(sizeof(SLL));
 75     s->data = *e;
 76     s->next = p->next;
 77     p->next = s;
 78 
 79     return 1;
 80 }
 81 
 82 // 删除链表中指定数据元素
 83 int Delete_LinkList(Slist L, int i, int* e)
 84 {
 85     Slist p, q;
 86     p = L;
 87     int j = 0;
 88 
 89     while (p->next && j < i - 1)
 90     {
 91         p = p->next;
 92         ++j;
 93     }
 94 
 95     if (!(p->next) || j > i - 1)
 96     {
 97         return 0;
 98     }
 99 
100 
101     q = p->next;
102     p->next = q->next;
103     *e = q->data;
104 
105     free(q);
106     return 1;
107 }
108 
109 // 显示链表元素的内容
110 int Print_LinkList(Slist L, char* s)
111 {
112     Slist p;
113     
114     p = L->next;
115     if (p == NULL)
116     {
117         cout << "该链表为空!" << endl;
118         return 0;
119     }
120 
121     while (p != NULL)
122     {
123         cout << p->data << " ";
124         p = p->next;
125     }
126     cout << endl;
127     return 1;
128 }
129 
130 int main()
131 {
132     // 创建并初始化链表
133     SLL L;
134     cout << "请输入五个节点的数据" << endl;
135     New_LinkList(&L, 5);
136     Print_LinkList(&L, (char*)"初始化链表:");
137 
138     int s, v;
139 
140     // 插入数据
141     cout << "请输入数据插入的位置和值:";
142     cin >> s >> v;
143     Isert_LinkList(&L, s, &v);
144     Print_LinkList(&L, (char*)"插入后的节点数:");
145 
146 
147     // 查询数据
148     cout << "请输入数据查询的位置:";
149     cin >> s;
150     GetElem_LinkList(&L, s, &v);
151     cout << "" << s << "个数据是:" << v << endl;
152 
153     // 删除出数据
154     cout << "请输入数据删除的位置:";
155     cin >> s;
156     if (Delete_LinkList(&L, s, &v))
157     {
158         cout << "数据删除成功,你所删除的数据是:" << v << endl;
159     }
160     else
161     {
162         cout << "数据删除失败!" << endl;
163     }
164     Print_LinkList(&L, (char*)"删除后的链表:");
165 
166 
167     return 0;
168 }

 尾插法

从一个空表L开始,将新结点逐个插入到链表的尾部,尾指针r指向链表的尾结点。
初始时,r同L均指向头结点。每读入一个数据元素则申请一个新结点,将新结点插入到尾结点后,r指向新结点。

 

  1 #include <iostream>
  2 using namespace std;
  3 
  4 #define ERROR   0
  5 #define OK      1
  6 
  7 
  8 // 链表节点的结构体
  9 typedef struct LNode
 10 {
 11     int data;            // 数据域
 12     struct LNode* next;    // 指针域
 13 }SLL , * SLNode;
 14 
 15 
 16 // 新建链表,确认链表的长度
 17 void New_LinkList(SLNode L, int n)
 18 {
 19     int i;
 20     int v;
 21 
 22     SLNode p,r;        // 新建单链表
 23     L->next = NULL;
 24     r = L;          //尾指针r指向头节点
 25 
 26     //链表的尾插法
 27     for (int i = n; i > 0; i--)
 28     {
 29         p = (SLNode)malloc(sizeof(SLL));  //生成新结点
 30         cin >> v;
 31         p->data = v;                  //输入元素值
 32         p->next = NULL; r->next = p;  //插入到表尾
 33         r = p;                        //r指向新的尾结点
 34         //插入的结点p是尾结点,所以要使r指向p,才能让再次插入的
 35         //结点顺利执行第31行。
 36     }
 37 }
 38 
 39 
 40 // 获取链表中指定位置的数据元素
 41 int GetElem_LinkList(SLNode L, int i, int *e)
 42 {
 43     SLNode p;
 44     p = L->next;
 45     int j = 1;
 46 
 47     while (p && j < i)
 48     {
 49         p = p->next;
 50         ++j;
 51     }
 52 
 53     if (!p || j > i)
 54     {
 55         return ERROR;
 56     }
 57 
 58     *e = p->data;
 59     return OK;
 60 }
 61 
 62 
 63 // 在链表中指定位置插入数据
 64 int Isert_LinkList(SLNode L, int i, int* e)
 65 {
 66     SLNode p, s;
 67     p = L;
 68     int j = 0;
 69 
 70     while (p && j < i - 1)
 71     {
 72         p = p->next;
 73         ++j;
 74     }
 75 
 76     if (!p || j > i - 1)
 77     {
 78         return ERROR;
 79     }
 80 
 81     s = (SLNode)malloc(sizeof(SLL));
 82     s->data = *e;
 83     s->next = p->next;
 84     p->next = s;
 85 
 86     return OK;
 87 }
 88 
 89 
 90 // 删除链表中制定数据元素
 91 int Delete_LinkList(SLNode L, int i, int* e)
 92 {
 93     SLNode p, q;
 94     p = L;
 95     int j = 0;
 96 
 97     while (p->next && j < i - 1)
 98     {
 99         p = p->next;
100         ++j;
101     }
102 
103     if (!(p->next) || j > i - 1)
104     {
105         return ERROR;
106     }
107 
108 
109     q = p->next;
110     p->next = q->next;
111     *e = q->data;
112 
113     free(q);
114     return OK;
115 }
116 
117 
118 // 显示链表元素的内容
119 int Print_LinkList(SLNode L, char* s)
120 {
121     SLNode p;
122 
123     p = L->next;
124     if (p == NULL)
125     {
126         cout << "该链表为空!" << endl;
127         return ERROR;
128     }
129 
130     while (p != NULL)
131     {
132         cout << p->data << " ";
133         p = p->next;
134     }
135     cout << endl;
136     return OK;
137 }
138 
139 
140 int main()
141 {
142     // 创建并初始化链表
143     struct LNode L;
144     cout << "请输入五个节点的数据" << endl;
145     New_LinkList(&L, 5);
146     Print_LinkList(&L, (char*)"初始化链表:");
147 
148     int s, v;
149 
150     // 插入数据
151     cout << "请输入数据插入的位置和值:";
152     cin >> s >> v;
153     Isert_LinkList(&L, s, &v);
154     Print_LinkList(&L, (char*)"插入后的节点数:");
155 
156 
157     // 查询数据
158     cout << "请输入数据查询的位置:";
159     cin >> s;
160     GetElem_LinkList(&L, s, &v);
161     cout << "" << s << "个数据是:" << v << endl;
162 
163     // 删除出数据
164     cout << "请输入数据删除的位置:";
165     cin >> s;
166     if (Delete_LinkList(&L, s, &v))
167     {
168         cout << "数据删除成功,你所删除的数据是:" << v << endl;
169     }
170     else
171     {
172         cout << "数据删除失败!" << endl;
173     }
174     Print_LinkList(&L, (char*)"删除后的链表:");
175 
176 
177     return 0;
178 }

 

posted @ 2019-10-27 23:21  yg_staring  阅读(6718)  评论(0编辑  收藏  举报