前面說了帶頭結點與不帶頭結點這兩種單鏈表的一些情況,同時我們知道設置了頭結點的單鏈表可以降低程序複雜性與減少BUG出現率,那麼接下來我們來探討一下關於帶頭結點的單鏈表的一些基本操作,這很重要。
線性表的單鏈表存儲結構定義如下:
1 |
struct
LNode |
2 |
{ |
3 |
ElemType data; |
4 |
LNode *next; |
5 |
}; |
6 |
typedef
LNode *LinkList; // 另一種定義LinkList的方法 |
以下是帶有頭結點的單鏈表的12個基本操作:
001 |
void
InitList(LinkList &L) |
002 |
{ // 操作結果:構造一個空的線性表L |
003 |
L=(LinkList) malloc ( sizeof (LNode));
// 產生頭結點,並使L指向此頭結點 |
004 |
if (!L)
// 存儲分配失敗 |
005 |
exit (OVERFLOW); |
006 |
L->next=NULL;
// 頭結點的指針域爲空 |
007 |
} |
008 |
009 |
void
DestroyList(LinkList &L) |
010 |
{ // 初始條件:線性表L已存在。操作結果:銷燬線性表L |
011 |
LinkList q; |
012 |
while (L)
// L指向結點(非空) |
013 |
{ q=L->next;
// q指向首元結點 |
014 |
free (L);
// 釋放頭結點 |
015 |
L=q;
// L指向原首元結點,現頭結點 |
016 |
} |
017 |
} |
018 |
019 |
void
ClearList(LinkList L) // 不改變L |
020 |
{ // 初始條件:線性表L已存在。操作結果:將L重置爲空表 |
021 |
LinkList p=L->next;
// p指向第1個結點 |
022 |
L->next=NULL;
// 頭結點指針域爲空 |
023 |
DestroyList(p);
// 銷燬p所指的單鏈表 |
024 |
} |
025 |
026 |
Status ListEmpty(LinkList L) |
027 |
{ // 初始條件:線性表L已存在。操作結果:若L爲空表,則返回TRUE,否則返回FALSE |
028 |
if (L->next)
// 非空 |
029 |
return
FALSE; |
030 |
else |
031 |
return
TRUE; |
032 |
} |
033 |
034 |
int
ListLength(LinkList L) |
035 |
{ // 初始條件:線性表L已存在。操作結果:返回L中數據元素的個數 |
036 |
int
i=0; // 計數器初值爲0 |
037 |
LinkList p=L->next;
// p指向第1個結點 |
038 |
while (p)
// 未到表尾 |
039 |
{ i++;
// 計數器+1 |
040 |
p=p->next;
// p指向下一個結點 |
041 |
} |
042 |
return
i; |
043 |
} |
044 |
045 |
Status GetElem(LinkList L, int
i,ElemType &e) // 算法2.8 |
046 |
{ // L爲帶頭結點的單鏈表的頭指針。當第i個元素存在時,其值賦給e並返回OK;否則返回ERROR |
047 |
int
j=1; // 計數器初值爲1 |
048 |
LinkList p=L->next;
// p指向第1個結點 |
049 |
while (p&&j<i)
// 順指針向後查找,直到p指向第i個結點或p爲空(第i個結點不存在) |
050 |
{ j++;
// 計數器+1 |
051 |
p=p->next;
// p指向下一個結點 |
052 |
} |
053 |
if (!p||j>i)
// 第i個結點不存在 |
054 |
return
ERROR; |
055 |
e=p->data;
// 取第i個元素的值賦給e |
056 |
return
OK; |
057 |
} |
058 |
059 |
int
LocateElem(LinkList L,ElemType e,Status(*compare)(ElemType,ElemType)) |
060 |
{ // 初始條件:線性表L已存在,compare()是數據元素判定函數(滿足爲1,否則爲0) |
061 |
// 操作結果:返回L中第1個與e滿足關係compare()的數據元素的位序。 |
062 |
// 若這樣的數據元素不存在,則返回值爲0 |
063 |
int
i=0; // 計數器初值爲0 |
064 |
LinkList p=L->next;
// p指向第1個結點 |
065 |
while (p)
// 未到表尾 |
066 |
{ i++;
// 計數器+1 |
067 |
if (compare(p->data,e))
// 找到這樣的數據元素 |
068 |
return
i; // 返回其位序 |
069 |
p=p->next;
// p指向下一個結點 |
070 |
} |
071 |
return
0; // 滿足關係的數據元素不存在 |
072 |
} |
073 |
074 |
Status PriorElem(LinkList L,ElemType cur_e,ElemType &pre_e) |
075 |
{ // 初始條件:線性表L已存在 |
076 |
// 操作結果:若cur_e是L的數據元素,且不是第一個,則用pre_e返回它的前驅,返回OK, |
077 |
// 否則操作失敗,pre_e無定義,返回ERROR |
078 |
LinkList q,p=L->next;
// p指向第1個結點 |
079 |
while (p->next)
// p所指結點有後繼 |
080 |
{ q=p->next;
// q指向p的後繼 |
081 |
if (q->data==cur_e)
// p的後繼爲cur_e |
082 |
{ pre_e=p->data;
// 將p所指元素的值賦給pre_e |
083 |
return
OK; // 成功返回OK |
084 |
} |
085 |
p=q;
// p的後繼不爲cur_e,p向後移 |
086 |
} |
087 |
return
ERROR; // 操作失敗,返回ERROR |
088 |
} |
089 |
090 |
Status NextElem(LinkList L,ElemType cur_e,ElemType &next_e) |
091 |
{ // 初始條件:線性表L已存在 |
092 |
// 操作結果:若cur_e是L的數據元素,且不是最後一個,則用next_e返回它的後繼,返回OK, |
093 |
// 否則操作失敗,next_e無定義,返回ERROR |
094 |
LinkList p=L->next;
// p指向第1個結點 |
095 |
while (p->next)
// p所指結點有後繼 |
096 |
{
if (p->data==cur_e)
// p所指結點的值爲cur_e |
097 |
{ next_e=p->next->data;
// 將p所指結點的後繼結點的值賦給next_e |
098 |
return
OK; // 成功返回OK |
099 |
} |
100 |
p=p->next;
// p指向下一個結點 |
101 |
} |
102 |
return
ERROR; // 操作失敗,返回ERROR |
103 |
} |
104 |
105 |
Status ListInsert(LinkList L, int
i,ElemType e) // 算法2.9。不改變L |
106 |
{ // 在帶頭結點的單鏈線性表L中第i個位置之前插入元素e |
107 |
int
j=0; // 計數器初值爲0 |
108 |
LinkList s,p=L;
// p指向頭結點 |
109 |
while (p&&j<i-1)
// 尋找第i-1個結點 |
110 |
{ j++;
// 計數器+1 |
111 |
p=p->next;
// p指向下一個結點 |
112 |
} |
113 |
if (!p||j>i-1)
// i小於1或者大於表長 |
114 |
return
ERROR; // 插入失敗 |
115 |
s=(LinkList) malloc ( sizeof (LNode));
// 生成新結點,以下將其插入L中 |
116 |
s->data=e;
// 將e賦給新結點 |
117 |
s->next=p->next;
// 新結點指向原第i個結點 |
118 |
p->next=s;
// 原第i-1個結點指向新結點 |
119 |
return
OK; // 插入成功 |
120 |
} |
121 |
122 |
Status ListDelete(LinkList L, int
i,ElemType &e) // 算法2.10。不改變L |
123 |
{ // 在帶頭結點的單鏈線性表L中,刪除第i個元素,並由e返回其值 |
124 |
int
j=0; // 計數器初值爲0 |
125 |
LinkList q,p=L;
// p指向頭結點 |
126 |
while (p->next&&j<i-1)
// 尋找第i個結點,並令p指向其前驅 |
127 |
{ j++;
// 計數器+1 |
128 |
p=p->next;
// p指向下一個結點 |
129 |
} |
130 |
if (!p->next||j>i-1)
// 刪除位置不合理 |
131 |
return
ERROR; // 刪除失敗 |
132 |
q=p->next;
// q指向待刪除結點 |
133 |
p->next=q->next;
// 待刪結點的前驅指向待刪結點的後繼 |
134 |
e=q->data;
// 將待刪結點的值賦給e |
135 |
free (q);
// 釋放待刪結點 |
136 |
return
OK; // 刪除成功 |
137 |
} |
138 |
139 |
void
ListTraverse(LinkList L, void (*visit)(ElemType)) |
140 |
// visit的形參類型爲ElemType,與bo2-1.cpp中相應函數的形參類型ElemType&不同 |
141 |
{ // 初始條件:線性表L已存在。操作結果:依次對L的每個數據元素調用函數visit() |
142 |
LinkList p=L->next;
// p指向第1個結點 |
143 |
while (p)
// p所指結點存在 |
144 |
{ visit(p->data);
// 對p所指結點調用函數visit() |
145 |
p=p->next;
// p指向下一個結點 |
146 |
} |
147 |
printf ( "\n" ); |
148 |
} |