文章目錄 簡介 動態順序表結構體 1.頭插功能 2.頭刪功能 3.尾插功能 4.尾刪功能 5.查找功能 6.插入功能 6.1 指定位置之(前)去插入一個節點 6.2 指定位置之(后)去插入一個節點 7.刪除功能 7.1 刪除指定位置的數據-時間復雜度O(N) 7.2 刪除指定位置后一個位置的數據-時間復雜度O(1) 8. 釋放鏈表緩存 9. 打印鏈表的值 10.此程序共包含3個文件,2個.c文件和1個.h文件 10.1 SList.h文件 10.2 SList.c文件 10.3 test.c文件
簡介
本文主要介紹鏈表的頭插、頭刪、尾插、尾刪、查找、插入和刪除,提供全部的.c和.h文件,確保使用者直接復制粘貼到編譯器上即可直接運行程序。
動態順序表結構體
typedef int SLTDateType; typedef struct SListNode
{ SLTDateType data; struct SListNode * next;
} SLTNode;
1.頭插功能
思路是將節點的首地址賦值到新申請節點的next中。
void SListPushFront ( SLTNode* * ppHead, SLTDateType x)
{ assert ( ppHead != NULL ) ; SLTNode* newNode = CreatListNode ( x) ; newNode-> next = * ppHead; * ppHead = newNode; return ;
}
開辟一個新的節點,并將要插入的值放心節點對應的data中。
SLTNode* CreatListNode ( SLTDateType x)
{ SLTNode* newNode = ( SLTNode* ) malloc ( sizeof ( SLTNode) ) ; if ( NULL == newNode) { printf ( "CreatListNode malloc fail\n" ) ; exit ( - 1 ) ; } newNode-> data = x; newNode-> next = NULL ; return newNode;
}
2.頭刪功能
思路是將下一個節點的地址賦值到頭節點地址上,將當前節點free掉。
void SListPopFront ( SLTNode* * ppHead)
{ assert ( ppHead != NULL ) ; SLTNode* next = ( * ppHead) -> next; free ( * ppHead) ; * ppHead = next; return ;
}
3.尾插功能
思路是先檢查輸入*ppHead是否為空,不為空就找到鏈表的尾節點進行新節點的插入。
void SListPushBack ( SLTNode* * ppHead, SLTDateType x)
{ assert ( ppHead != NULL ) ; SLTNode* newNode = CreatListNode ( x) ; if ( * ppHead == NULL ) { * ppHead = newNode; } else { SLTNode* tail = * ppHead; while ( tail-> next != NULL ) { tail = tail-> next; } tail-> next = newNode; } return ;
}
4.尾刪功能
思路是釋放節點時,要將下一個節點的地址保存好再釋放當前節點。
void SListPopBack ( SLTNode* * ppHead)
{ assert ( ppHead != NULL ) ; if ( ( * ppHead) -> next == NULL ) { free ( * ppHead) ; * ppHead = NULL ; } else { SLTNode* tail = * ppHead; SLTNode* pre = NULL ; while ( tail-> next != NULL ) { pre = tail; tail = tail-> next; } pre-> next = NULL ; free ( tail) ; tail = NULL ; } return ;
}
5.查找功能
思路是遍歷,找到節點后返回當前節點的地址,找不到就返回NULL。
SLTNode* SListFind ( SLTNode* pHead, SLTDateType x)
{ assert ( pHead != NULL ) ; SLTNode* cur = pHead; while ( cur) { if ( cur-> data == x) { return cur; } else { cur = cur-> next; } } return NULL ;
}
6.插入功能
6.1 指定位置之(前)去插入一個節點
此方法是比較笨的方法,為了節約資源應該將數據往指定位置的后邊插入。
SLTNode* SListInsert ( SLTNode* * ppHead, SLTNode* pos, SLTDateType x)
{ assert ( ppHead != NULL ) ; assert ( pos != NULL ) ; SLTNode* newNode = CreatListNode ( x) ; if ( * ppHead == pos) { newNode-> next = * ppHead; * ppHead = newNode; } else { SLTNode* posPrev = * ppHead; while ( posPrev-> next != pos) { posPrev = posPrev-> next; } posPrev-> next = newNode; newNode-> next = pos; } return NULL ;
}
6.2 指定位置之(后)去插入一個節點
此方法是常用的插入方式,時間復雜度是O(1)。
SLTNode* SListInsertAfter ( SLTNode* pos, SLTDateType x)
{ assert ( pos != NULL ) ; SLTNode* newNode = CreatListNode ( x) ; newNode-> next = pos-> next; pos-> next = newNode; return NULL ;
}
7.刪除功能
7.1 刪除指定位置的數據-時間復雜度O(N)
此方法需要記住當前節點前一個的節點地址,會多耗費時間資源,時間復雜度O(N)。
SLTNode* SListErase ( SLTNode* * ppHead, SLTNode* pos)
{ assert ( ppHead != NULL ) ; assert ( pos != NULL ) ; if ( * ppHead == pos) { SListPopFront ( ppHead) ; } else { SLTNode* prev = * ppHead; while ( prev-> next != pos) { prev = prev-> next; } prev-> next = pos-> next; free ( pos) ; pos = NULL ; } return NULL ;
}
7.2 刪除指定位置后一個位置的數據-時間復雜度O(1)
此方法需要記住當前節點前一個的節點地址,會多耗費時間資源,時間復雜度O(1)。
SLTNode* SListEraseAfter ( SLTNode* pos)
{ assert ( pos-> next != NULL ) ; SLTNode* next = pos-> next; pos-> next = next-> next; free ( next) ; next = NULL ; return NULL ;
}
8. 釋放鏈表緩存
思路將下一個節點的地址先記住,然后釋放當前節點。再將保存的地址賦值到當前節點循環釋放緩存。
SLTNode* SListDestory ( SLTNode* * ppHead)
{ assert ( ppHead != NULL ) ; SLTNode* cur = * ppHead; while ( cur) { SLTNode* next = cur-> next; free ( cur) ; cur = next; } * ppHead = NULL ; return NULL ;
}
9. 打印鏈表的值
void SListTPrint ( SLTNode* pHead)
{ SLTNode* cur = pHead; while ( cur != NULL ) { printf ( "%d->" , cur-> data) ; cur = cur-> next; } return ;
}
10.此程序共包含3個文件,2個.c文件和1個.h文件
10.1 SList.h文件
文件中包含了函數功能的頭文件以及對應的結構體。
# pragma once
# include <stdio.h>
# include <stdlib.h>
# include <assert.h> typedef int SLTDateType; typedef struct SListNode
{ SLTDateType data; struct SListNode * next;
} SLTNode; void SListTPrint ( SLTNode * pHead) ;
void SListPushBack ( SLTNode* * ppHead, SLTDateType x) ;
void SListPushFront ( SLTNode* * ppHead, SLTDateType x) ; void SListPopBack ( SLTNode* * ppHead) ;
void SListPopFront ( SLTNode* * ppHead) ; SLTNode* SListFind ( SLTNode* pHead, SLTDateType x) ;
SLTNode* SListInsert ( SLTNode* * ppHead, SLTNode* pos, SLTDateType x) ;
SLTNode* SListInsertAfter ( SLTNode* pos, SLTDateType x) ;
SLTNode* SListErase ( SLTNode* * ppHead, SLTNode* pos) ;
SLTNode* SListEraseAfter ( SLTNode* pos) ;
SLTNode* SListDestory ( SLTNode* * ppHead) ; SLTNode* CreatListNode ( SLTDateType x) ;
10.2 SList.c文件
文件中包含了功能函數的具體實現方式。
# define _CRT_SECURE_NO_WARNINGS
# include "SList.h"
void SListPushBack ( SLTNode* * ppHead, SLTDateType x)
{ assert ( ppHead != NULL ) ; SLTNode* newNode = CreatListNode ( x) ; if ( * ppHead == NULL ) { * ppHead = newNode; } else { SLTNode* tail = * ppHead; while ( tail-> next != NULL ) { tail = tail-> next; } tail-> next = newNode; } return ;
}
void SListPushFront ( SLTNode* * ppHead, SLTDateType x)
{ assert ( ppHead != NULL ) ; SLTNode* newNode = CreatListNode ( x) ; newNode-> next = * ppHead; * ppHead = newNode; return ;
}
SLTNode* CreatListNode ( SLTDateType x)
{ SLTNode* newNode = ( SLTNode* ) malloc ( sizeof ( SLTNode) ) ; if ( NULL == newNode) { printf ( "CreatListNode malloc fail\n" ) ; exit ( - 1 ) ; } newNode-> data = x; newNode-> next = NULL ; return newNode;
}
void SListPopBack ( SLTNode* * ppHead)
{ assert ( ppHead != NULL ) ; if ( ( * ppHead) -> next == NULL ) { free ( * ppHead) ; * ppHead = NULL ; } else { SLTNode* tail = * ppHead; SLTNode* pre = NULL ; while ( tail-> next != NULL ) { pre = tail; tail = tail-> next; } pre-> next = NULL ; free ( tail) ; tail = NULL ; } return ;
}
void SListPopFront ( SLTNode* * ppHead)
{ assert ( ppHead != NULL ) ; SLTNode* next = ( * ppHead) -> next; free ( * ppHead) ; * ppHead = next; return ;
}
SLTNode* SListFind ( SLTNode* pHead, SLTDateType x)
{ assert ( pHead != NULL ) ; SLTNode* cur = pHead; while ( cur) { if ( cur-> data == x) { return cur; } else { cur = cur-> next; } } return NULL ;
}
SLTNode* SListInsert ( SLTNode* * ppHead, SLTNode* pos, SLTDateType x)
{ assert ( ppHead != NULL ) ; assert ( pos != NULL ) ; SLTNode* newNode = CreatListNode ( x) ; if ( * ppHead == pos) { newNode-> next = * ppHead; * ppHead = newNode; } else { SLTNode* posPrev = * ppHead; while ( posPrev-> next != pos) { posPrev = posPrev-> next; } posPrev-> next = newNode; newNode-> next = pos; } return NULL ;
}
SLTNode* SListInsertAfter ( SLTNode* pos, SLTDateType x)
{ assert ( pos != NULL ) ; SLTNode* newNode = CreatListNode ( x) ; newNode-> next = pos-> next; pos-> next = newNode; return NULL ;
}
SLTNode* SListErase ( SLTNode* * ppHead, SLTNode* pos)
{ assert ( ppHead != NULL ) ; assert ( pos != NULL ) ; if ( * ppHead == pos) { SListPopFront ( ppHead) ; } else { SLTNode* prev = * ppHead; while ( prev-> next != pos) { prev = prev-> next; } prev-> next = pos-> next; free ( pos) ; pos = NULL ; } return NULL ;
}
SLTNode* SListEraseAfter ( SLTNode* pos)
{ assert ( pos-> next != NULL ) ; SLTNode* next = pos-> next; pos-> next = next-> next; free ( next) ; next = NULL ; return NULL ;
}
SLTNode* SListDestory ( SLTNode* * ppHead)
{ assert ( ppHead != NULL ) ; SLTNode* cur = * ppHead; while ( cur) { SLTNode* next = cur-> next; free ( cur) ; cur = next; } * ppHead = NULL ; return NULL ;
}
void SListTPrint ( SLTNode* pHead)
{ SLTNode* cur = pHead; while ( cur != NULL ) { printf ( "%d->" , cur-> data) ; cur = cur-> next; } return ;
}
10.3 test.c文件
用來進行相應功能的測試,分別測試尾插、尾刪和頭插、頭刪等功能。
# define _CRT_SECURE_NO_WARNINGS
# include <stdio.h>
# include "SList.h" void Test1 ( )
{ SLTNode* SList = NULL ; SListPushBack ( & SList, 1 ) ; SListPushBack ( & SList, 2 ) ; SListPushBack ( & SList, 3 ) ; SListPushBack ( & SList, 4 ) ; SListPopBack ( & SList) ; SListTPrint ( SList) ; printf ( "NULL\n" ) ; return ;
} void Test2 ( )
{ SLTNode* SList = NULL ; SListPushFront ( & SList, 1 ) ; SListPushFront ( & SList, 2 ) ; SListPushFront ( & SList, 3 ) ; SListPopFront ( & SList) ; SListTPrint ( SList) ; printf ( "NULL" ) ; return ;
} void Test3 ( )
{ SLTNode* SList = NULL ; SLTNode* pos = NULL ; int i = 1 ; SListPushBack ( & SList, 1 ) ; SListPushBack ( & SList, 5 ) ; SListPushBack ( & SList, 2 ) ; SListPushBack ( & SList, 3 ) ; SListPushBack ( & SList, 2 ) ; pos = SListFind ( SList, 2 ) ; while ( pos) { printf ( "第%d個pos節點的:%p->%d\n" , i++ , pos-> next, pos-> data) ; if ( pos-> next) { pos = SListFind ( pos-> next, 2 ) ; } else { break ; } } pos = SListFind ( SList, 5 ) ; if ( pos) { SListInsert ( & SList, pos, 20 ) ; } pos = SListFind ( SList, 5 ) ; if ( pos) { SListInsertAfter ( pos, 100 ) ; } SListTPrint ( SList) ; printf ( "NULL" ) ; return ;
} int main ( )
{ Test1 ( ) ; return 0 ;
}
這里代碼大家可以自己拷貝到VS編譯器中,Test1(),Test2(),Test3(),分別打開注釋看一下效果,本人親測過,可以直接運行出結果的。