請使用 VC++6 打開 main.dsw 文件,然後點擊運行按鈕(就是那個紅色的歎號)編譯執行。
雙鏈表
線性表的插入運算(雙向鏈表存儲結構)
在雙向循環鏈表L的位置p處插入一個新元素x的過程Insert可實現如下。
在雙向循環鏈表L的位置p處插入一個新元素x的過程Insert可實現如下。
算法:
typedef struct dnode {
elemtype data;
struct dnode *prior, *next;
} DNODE;
typedef struct dnode {
elemtype data;
struct dnode *prior, *next;
} DNODE;
int link_ins(DNODE **head, int i, elemtype x)
{
int j = 1; /* 雙向循環鏈表 */
DNODE *p, *q;
q = malloc( sizeof *p );
q->data = x;
if ( i == 0 ) {
q->prior = *head;
q->next = *head;
*head = q;
return 0;
}
p = *head;
j = 0;
while ( ++j < i && p != NULL )
p = p->next;
if ( i < 0 || j < i )
return 1;
else {
q->next = p->next;
p->next = q;
p->next->prior = q;
q->prior = p;
return 0;
}
}
分析:在上面的插入算法中,不需要移動別的元素,但必須
從頭開始查找第i結點的地址,一旦找到插入位置,則插入結點
只需兩條語句就可完成。該算法的時間複雜度爲O(n)
1、雙向鏈表(Doubly Linked List)
雙(向)鏈表中有兩條方向不同的鏈,即每個結點中除next域存放後繼結點地址外,還增加一個指向其直接前趨的指針域prior。
雙(向)鏈表中有兩條方向不同的鏈,即每個結點中除next域存放後繼結點地址外,還增加一個指向其直接前趨的指針域prior。
注意:
①雙鏈表由頭指針head惟一確定的。
②帶頭結點的雙鏈表的某些運算變得方便。
③將頭結點和尾結點鏈接起來,爲雙(向)循環鏈表。
①雙鏈表由頭指針head惟一確定的。
②帶頭結點的雙鏈表的某些運算變得方便。
③將頭結點和尾結點鏈接起來,爲雙(向)循環鏈表。
2、雙向鏈表的結點結構和形式描述
①結點結構(見上圖a)
②形式描述
typedef struct dlistnode {
DataType data;
struct dlistnode *prior,*next;
} DListNode;
typedef DListNode *DLinkList;
DLinkList head;
①結點結構(見上圖a)
②形式描述
typedef struct dlistnode {
DataType data;
struct dlistnode *prior,*next;
} DListNode;
typedef DListNode *DLinkList;
DLinkList head;
3、雙向鏈表的前插和刪除本結點操作
由於雙鏈表的對稱性,在雙鏈表能能方便地完成各種插入、刪除操作。
①雙鏈表的前插操作
由於雙鏈表的對稱性,在雙鏈表能能方便地完成各種插入、刪除操作。
①雙鏈表的前插操作
void DInsertBefore(DListNode *p, DataType x)
{ /* 在帶頭結點的雙鏈表中,將值爲x的新結點插入*p之前,設p≠NULL */
DListNode *s = malloc( sizeof(DListNode) ); /* ① */
s->data = x; /* ② */
s->prior = p->prior; /* ③ */
s->next = p; /* ④ */
p->prior->next = s; /* ⑤ */
p->prior = s; /* ⑥ */
}
②雙鏈表上刪除結點*p自身的操作
{ /* 在帶頭結點的雙鏈表中,將值爲x的新結點插入*p之前,設p≠NULL */
DListNode *s = malloc( sizeof(DListNode) ); /* ① */
s->data = x; /* ② */
s->prior = p->prior; /* ③ */
s->next = p; /* ④ */
p->prior->next = s; /* ⑤ */
p->prior = s; /* ⑥ */
}
②雙鏈表上刪除結點*p自身的操作
void DDeleteNode(DListNode *p)
{ /* 在帶頭結點的雙鏈表中,刪除結點*p,設*p爲非終端結點 */
p->prior->next = p->next; /* ① */
p->next->prior = p->prior; /* ② */
free(p); /* ③ */
}
注意:
與單鏈表上的插入和刪除操作不同的是,在雙鏈表中插入和刪除必須同時修改兩個方向上的指針。
上述兩個算法的時間複雜度均爲O(1)。
{ /* 在帶頭結點的雙鏈表中,刪除結點*p,設*p爲非終端結點 */
p->prior->next = p->next; /* ① */
p->next->prior = p->prior; /* ② */
free(p); /* ③ */
}
注意:
與單鏈表上的插入和刪除操作不同的是,在雙鏈表中插入和刪除必須同時修改兩個方向上的指針。
上述兩個算法的時間複雜度均爲O(1)。