标签:
首先要强调的是,ADT没有变化,只是实现上的变化。
不带头结点的实现比带头结点的实现稍微复杂一些,尤其体现在插入(第58-60行)和删除(第88-91行),要单独处理表头改变的情况。而带头结点的链表表头不会变化,总是指向头结点。
其他操作的不同之处同学们自行比较。
下面的问题会帮助你的理解:
第83行 while(p && j < i - 1) { 而教材上带头结点的实现为while(p->next && j < i - 1) {
为什么会有这种区别?
点击看答案
不带头结点的方式不能保证p不为空,p->next自然可能产生问题。 带头结点的实现可以保证这一点。 另外,书上采用p->next的动机也非常明显,不仅要找到第i-1个结点(循环结束后的p指向的结点), 而且要保证第i个结点(即p->next)也存在。 所以不带头结点的方式第87行才有下面的代码 if(!p || !p->next || i < 1)
1 #include<iostream>
2 using namespace std;
3
4 #define OK 1
5 #define ERROR 0
6 #define OVERFLOW -2
7 typedef int Status; //Status 是函数返回值类型,其值是函数结果状态代码。
8 typedef int ElemType; //ElemType 为可定义的数据类型,此设为int类型
9
10 typedef struct LNode {
11 ElemType data; //结点的数据域
12 struct LNode *next; //结点的指针域
13 } LNode, *LinkList; //LinkList为指向结构体LNode的指针类型
14
15
16 Status InitList_L(LinkList &L) //算法2.5 单链表的初始化
17 {
18 //构造一个空的单链表L
19 L = NULL;
20 return OK;
21 }
22
23 Status GetElem_L(LinkList L, int i, ElemType &e) //算法2.6 按序号查找
24 {
25 //在带头结点的单链表L中查找第i个元素
26 int j;
27 LNode *p;
28 p = L;
29 j = 1; //初始化,p指向第一个结点,j为计数器
30 while(j < i && p) { //顺链域向后扫描,直到p指向第i个元素或p为空
31 p = p->next;
32 ++j;
33 }
34 if(!p || j > i) return ERROR; //第i个元素不存在
35 e = p->data; //取第i个元素
36 return OK;
37 } //GetElem_L
38
39 LNode *LocateElem_L(LinkList L, ElemType e) //算法2.7 按值查找
40 {
41 //在带头结点的单链表L中查找值为e的元素
42 LNode *p;
43 p = L;
44 while(p && p->data != e)
45 p = p->next; //寻找满足条件的结点
46 return p; //返回L中的值为e的数据元素的位置,查找失败返回NULL
47 } //LocateElem_L
48
49 Status ListInsert_L(LinkList &L, int i, ElemType &e) //算法2.8 单链表的插入
50 {
51 //在带头结点的单链表L中第i个位置之前插入元素e
52 int j;
53 LNode *p, *s;
54 p = L;
55 j = 1; //与教材不同之处
56 s = new LNode; //生成新结点s
57 s->data = e; //将结点s的数据域置为e
58 if(i == 1) { //插在表头
59 s->next = L;
60 L = s; //修改表头
61 } else {
62 while(p && j < i - 1) {
63 p = p->next; //寻找第i-1个结点
64 ++j;
65 }
66 if(!p || j > i - 1) {
67 delete s;
68 return ERROR; //i大于表长+1或者小于1
69 }
70 s->next = p->next; //将结点s插入L中
71 p->next = s;
72 }
73 return OK;
74 } //ListInsert_L
75
76 Status ListDelete_L(LinkList &L, int i, ElemType &e) //算法2.9 单链表的删除
77 {
78 //在带头结点的单链表L中,删除第i个位置,并由e返回值
79 LNode *p, *q;
80 int j;
81 p = L;
82 j = 1;
83 while(p && j < i - 1) {
84 p = p->next; //寻找第i-1个结点
85 ++j;
86 }
87 if(!p || !p->next || i < 1) return ERROR; //i大于表长或者小于1, p->next==NULL为表长加一情形
88 if(i == 1) { //删除表头
89 e = p->data;
90 L = p->next;
91 delete p;
92 } else {
93 q = p->next; //临时保存被删结点的地址以备释放
94 p->next = q->next; //改变删除结点前驱结点的指针域
95 e = q->data; //保存删除结点的数据域
96 delete q; //释放删除结点的空间
97 }
98 return OK;
99 } //ListDelete_L
100
101
102 void CreateList_L(LinkList &L, int n) //算法2.11 后插法创建单链表
103 {
104 //正位序输入n个元素的值,建立到头结点的单链表L
105 LNode *r, *p;
106 L = NULL; //先建立一个带头结点的空链表
107 cout << "请输入 " << n << " 个数:\n";
108 for(int i = 0; i < n; i++) {
109 p = new LNode; //生成新结点
110 cin >> p->data; //输入元素值
111 p->next = NULL;
112 if(i == 0) { //第一个结点,表头
113 r = L = p;
114 } else {
115 r->next = p; //插入到表尾
116 r = p; //r指向新的尾结点
117 }
118 }
119 } //CreateList_L
120
121 int main()
122 {
123 int res, a, b, choose;
124 LNode *L, *p;
125 cout << "1. 建立链表\n";
126 cout << "2. 输入数据\n";
127 cout << "3. 按位置查找\n";
128 cout << "4. 按值查找\n";
129 cout << "5. 链表的插入\n";
130 cout << "6. 链表的删除\n";
131 cout << "7. 输出数据\n";
132 cout << "0. 退出\n\n";
133
134 choose = -1;
135 while(choose != 0) {
136 cout << "请选择:";
137 cin >> choose;
138 switch(choose) {
139 case 1: //建立一个单链表
140 if(InitList_L(L))
141 cout << "成功建立链表!\n\n";
142 break;
143 case 2: //使用后插法创建单链表
144 CreateList_L(L, 4);
145 cout << "成功创建链表!\n\n";
146 break;
147 case 3: //单链表的按序号查找
148 cout << "请输入一个位置用来查找:";
149 cin >> a;
150 if(GetElem_L(L, a, res))
151 cout << "查找成功!第" << a << "个数是:" << res << "\n\n";
152 else
153 cout << "查找失败\n\n";
154 break;
155 case 4: //单链表的按值查找
156 cout << "请输入一个数值用来查找:";
157 cin >> b;
158 if(LocateElem_L(L, b) != NULL)
159 cout << "查找成功\n\n";
160 else
161 cout << "查找失败! " << b << " 没有找到\n\n";
162 break;
163 case 5: //单链表的插入
164 cout << "请输入两个数分别代表插入的位置和数值:";
165 cin >> a >> b;
166 if(ListInsert_L(L, a, b))
167 cout << "成功将" << b << "插在第" << a << "个位置\n\n";
168 else
169 cout << "插入失败!\n\n";
170 break;
171 case 6: //单链表的删除
172 cout << "请输入一个位置用来删除:";
173 cin >> a;
174 if(ListDelete_L(L, a, res))
175 cout << "删除成功!被删除的数是:" << res << "\n\n";
176 else
177 cout << "删除失败!\n\n";
178 break;
179 case 7: //单链表的输出
180 cout << "现在链表里的数分别是:\n";
181 p = L;
182 while(p) {
183 cout << p->data << " ";
184 p = p->next;
185 }
186 cout << endl;
187 break;
188 }
189 }
190 return 0;
191 }
标签:
原文地址:http://www.cnblogs.com/4bytes/p/4432816.html