C 資料結構中單鏈表基本操作
C中的typedef
C中的typedef關鍵字作用是為一種資料型別定義一個新名字,這樣做的目的有兩個,一是給變數定義一個易記且意義明確的新名字,如:
typedef unsigned char BYTE;
把unsigned char型別自命名為BYTE。
另一個目的是簡化一些比較複雜的型別宣告,比如struct結構型別:
typedef struct student
{
int age;
int class;
}stu;
stu stu_1; // 這樣就比原來的方式少寫了一個struct,比較省事,尤其在大量使用的時候
struct student stu_1; //以上等價於這種定義,C中規定宣告struct物件時需要加struct關鍵字
使用typedef定義結構體指標
如下定義:
typedef struct TreeNode {
int Element;
struct TreeNode* LeftChild;
struct TreeNode* RightChild;
} Node,*PtrToTreeNode;
等價於:
給結構體 TreeNode 起一個別名為 Node;
給結構體指標 TreeNode* 起一個別名為 PtrToTreeNode; 即PtrToTreeNode實際上是一個指標
單鏈表基本操作
連結串列是一種線性儲存資料的結構(線性結構是一種資料的邏輯結構,其他還有樹結構、圖結構和集合結構)。連結串列的儲存內容在邏輯上連續,但物理上不一定連續。單向連結串列的組成包括:
- 表頭(head):只有指標域,沒有資料域;
- 結點(node):資料域+指標域;
- 表尾:只有資料域,沒有指標域(指標為NULL);
單鏈表結點(node)的定義:
struct node{
int num;
struct node* Pnext;
}
C語言中連結串列的實現主要依靠結構體和指標。
實現單鏈表的 建立、列印、計算長度、刪除指定結點、頭尾插入、連結串列遞增排序、逆序、清空連結串列等操作:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//定義單鏈表結點結構
typedef struct Node{
int data;
struct Node* next;
}node;
//建立帶表頭單向連結串列,表尾插入
node* createList(const int length){
node *head,*helper;
helper = head = (node *)malloc(sizeof(node));
for(int i=0;i<length;i++){
helper = helper->next = (node *)malloc(sizeof(node));
helper->data = i;
}
helper->next = NULL;
return head;
}
//列印連結串列
void printList(const node* list1){
const node* p=NULL;
p = list1->next; //有表頭連結串列指向表頭後的結點
while(p){
printf("%d\n",p->data);
p = p->next;
}
}
// 求連結串列長度
int length_list(const node* list1){
int n=0;
if(list1->next==NULL){
return n;
}
while(list1->next!=NULL){
n+=1;
list1=list1->next;
}
return n;
}
//刪除資料域值為key的結點
node* delete_key(node* list1, int key){
if(list1->next==NULL){
return list1; //如果為空直接返回
}
node* p, *del;
for(p=list1;p->next!=NULL&&p->next->data!=key;p=p->next);
if(p->next==NULL){
return list1; //如果到最後一個結點還沒有匹配到key,返回list1
}
del = p->next;
p->next=p->next->next;
free(del);
del = NULL;
return list1;
}
//在頭結點或尾結點插入資料key
node* insert_list(node* list1, int key, int head_or_end){
node* insert_key = (node*)malloc(sizeof(node));
insert_key->data = key;
if(head_or_end){
insert_key->next = list1->next;
list1->next = insert_key;
return list1;
}
else{
node* p = list1;
for(p = list1; p->next!=NULL;p=p->next);
p->next = insert_key;
insert_key->next = NULL;
return list1;
}
}
//單鏈表排序(表頭到表尾增大)
node* sort_list(node* list1){
int length = length_list(list1);
if(length==0){ //長度為0表示空連結串列,返回
return list1;
}
for(int i=1;i<length;i++){
node* p = list1->next;
for(int j=0;j<length-i;j++){
if(p->data>p->next->data){
p->data+=p->next->data;
p->next->data = p->data - p->next->data;
p->data = p->data - p->next->data;
}
p=p->next;
}
}
return list1;
}
//單鏈表逆序
node* reverse_list(node* list1){
if(list1==NULL||list1->next==NULL){
return list1;
}
node *p1, *p2, *p3;
node *head = (node*)malloc(sizeof(node));
p1 = list1;
p2 = p1->next;
while(p2!=NULL){
p3 = p2->next;
p2->next = p1;
p1 = p2;
p2 = p3;
}
list1->next->next=NULL;
head->next = p1;
list1 = head;
return list1;
}
//清空單鏈表
void delete_all(node* list1){
node* p1=NULL,*p2 = NULL;
p1 = list1->next;
while(p1->next!=NULL){
p2 = p1->next;
free(p1);
p1 = p2;
}
free(p2);
list1->next=NULL;
}
void main()
{
node* List1 =createList(5); //建立連結串列
printList(List1); //列印連結串列
printf("%d\n",length_list(List1)); //連結串列長度
List1 = delete_key(List1,3); //刪除連結串列結點
List1 = insert_list(List1,66,1); //頭結點插入資料
List1 = insert_list(List1,77,0); //尾結點插入資料
List1 = sort_list(List1); //連結串列遞增排序
printList(List1);
List1 = reverse_list(List1); //連結串列逆序
printList(List1);
delete_all(List1); //清空銷燬連結串列
printf("%d\n",length_list(List1));
return;
}
補充兩個操作: 頭插法和查詢中間結點:
// 表頭插入
node* create_list_headIN(const int length){
node* head = (node*)malloc(sizeof(node));
node* p;
for(int i=0;i<length;i++){
p = (node*)malloc(sizeof(node));
p->data = i;
p->next = head->next;
head->next = p;
}
head ;
return head;
}
//查詢連結串列中間結點
node* middle_node(node* list1){
node *p1,*p2;
p1 = p2 = list1;
while(p2 && p2->next){
p1 = p1->next;
p2 = p2->next->next;
}
printf("\n%d\n",p1->data);
return p1;
}