數據結構——鏈表(帶雙向循環鏈表)

鏈表

鏈表是一種物理存儲單元上非連續、非順序的存儲結構,數據元素的邏輯順序是通過鏈表中的指針鏈接次序實現的。鏈表由一系列結點(鏈表中每一個元素稱爲結點)組成,結點可以在運行時動態生成。每個結點包括兩個部分:一個是存儲數據元素的數據域,另一個是存儲下一個結點地址的指針域。
鏈表分別有一下的操作

typedef struct SListNode
{
	SLTDateType data;
	struct SListNode* next;
}SListNode;

// 動態申請一個節點
SListNode* BuySListNode(SLTDateType x);
// 單鏈表打印
void SListPrint(SListNode* plist);
// 單鏈表尾插
void SListPushBack(SListNode** pplist, SLTDateType x);
// 單鏈表的頭插
void SListPushFront(SListNode** pplist, SLTDateType x);
// 單鏈表的尾刪
void SListPopBack(SListNode** pplist);
// 單鏈表頭刪
void SListPopFront(SListNode** pplist);
// 單鏈表查找
SListNode* SListFind(SListNode* plist, SLTDateType x);
// 單鏈表在pos位置之後插入x
void SListInsertAfter(SListNode* pos, SLTDateType x);
// 單鏈表刪除pos位置之後的值
void SListEraseAfter(SListNode* pos);
// 單鏈表的銷燬
void SListDestory(SList* plist);

定義鏈表結構

這是帶頭指針而不帶頭節點的單鏈表定義方式,我們需要一個額外的結構體來定義。代碼如下

typedef struct node{
  int num;
  node* next;
}node;
typedef struct{
  struct node* head;
}singlelist;

鏈表的初始化

創建一個空鏈表,並且初始化它

void singleListInit(SingleList* sl)
{
	//空鏈表
	sl->_head = NULL;
}

Node* creatNode(Type data)
{
	Node* node = (Node*)malloc(sizeof(Node));
	node->_data = data;
	node->_next = NULL;
	return node;
}

鏈表的頭插

即每次都在頭指針的位置插入一個結點,需要改變指針指向,代碼如下

void singleListPushFront(SingleList* sl, Type data)
{
	Node* node = creatNode(data);
	//是否爲空表
	if (sl->_head == NULL)
	{
		sl->_head = node;
	}
	else
	{
		node->_next = sl->_head;
		sl->_head = node;
	}
}

鏈表的頭刪

既然是刪除,那麼切記不可忘記釋放空間,否則就會造成內存泄露,別切釋放的時候需要記錄當前要刪除的下一個結點,否則就會出現結點丟失

void singleListPopFront(SingleList* sl)
{
	if (sl->_head)
	{
		Node* cur = sl->_head;
		sl->_head = cur->_next;
		free(cur);
	}
}

錯誤的代碼形式之一如下

void singleListPop1(Node* head)
{
	if (head)
	{
		Node* newH = head->_next;
		free(head);
		head = newH;
	}
}

上述錯誤行成主要是爲傳入二級指針,正確寫法如下

void singleListPop(Node** head)
{
	if (*head)
	{
		Node* newH = (*head)->_next;
		free(*head);
		*head = newH;
	}
}

鏈表的尾插

尾插,顧名思義,每次在鏈表的末端進行插入節點的操作

void singleListPushBack(SingleList* sl, Type data)
{
	Node* node = creatNode(data);
	if (sl->_head == NULL)
		sl->_head = node;
	else
	{
		//找到最後一個數據
		// last   newNode
		Node* last = sl->_head;
		while (last->_next)
			last = last->_next;

		//尾插
		last->_next = node;
	}	
}

鏈表的尾刪

尾刪,即刪除尾部的結點,話不多說,代碼如下

void singleListPopBack(SingleList* sl)
{
	//找到最後一個節點,並且,修改被刪除節點的前驅節點的執行
	if (sl->_head)
	{
		//找到最後一個節點,遍歷的過程中,更新prev
		Node* prev = NULL;
		Node* tail = sl->_head;
		while (tail->_next)
		{
			prev = tail;
			tail = tail->_next;
		}
		//如果刪除的爲頭結點, 或者鏈表中只要一個節點
		//和下面判斷等價if (prev == NULL)
		if (tail == sl->_head)
			sl->_head = NULL;
		else
			prev->_next = NULL;

		free(tail);
	}
}

鏈表的結點插入

ps:這裏傳入的是找到所要插入結點的位置

void singleListInsertAfter(Node* pos, Type data)
{
	if (pos == NULL)
		return;
	// pos  newNode next
	Node* newNode = creatNode(data);
	//注意先後順序
	newNode->_next = pos->_next;
	pos->_next = newNode;
}

鏈表節點的刪除

傳入的參數也是找到的所要刪除的結點

void singleListEraseAfter(Node* pos)
{
	Node* next;
	if (pos == NULL)
		return;
	//pos  next
	next = pos->_next;
	//確保next非空指針, pos->_next->_next
	if (next)
	{
		pos->_next = next->_next;
		free(next);
	}
}

鏈表的刪除

刪除鏈表,要遍歷整個鏈表直至NULL每次刪除一個結點,直至刪除完

void singleListDestroy(SingleList* sl)
{
	Node* cur = sl->_head;
	while (cur)
	{
		Node* next = cur->_next;
		free(cur);
		cur = next;
	}
}

鏈表的打印

打印想必都能知道,也是遍歷這個鏈表,每次打印數據域的數據,知道遍歷到NULL

void singleListPrint(SingleList* sl)
{
	Node* cur = sl->_head;
	while (cur)
	{
		printf("%d ", cur->_data);
		cur = cur->_next;
	}
	printf("\n");
}

鏈表的基本操作就上述這些,此外還有一種常用的雙向循環鏈表的結構,在這裏就不多說雙向循環鏈表的結構我也寫了,代碼如下,供大家參考

雙向循環鏈表

#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
  int data;
  struct node* next;//指向後繼
  struct node* prev;//指向先驅
}noed;
typedef struct List
{
  node* head;
}list;
//生成結點
node* creatNode(int data)
{
  node* Node = (node*)malloc(sizeof(node));
	Node->prev = Node->next = NULL;
	Node->data = data;
	return Node;
}
//初始化鏈表
void litinit(list *ls)
{
  ls->head = creatNode(0);
  ls->head->next = ls->head;
  ls->head->prev = ls->head;
}
//尾插
void listPushBack(list* ls, int data)
{
  node* Node = creatNode(data);
  node* p = ls->head->prev;
  Node->next = p->next;
  p->next = Node;
  ls->head->prev = Node;
  Node->prev = p;
}
//頭插
void listPopFront(list* ls)
{
  if(ls->head->next == ls->head)
  return ;
  node* f = ls->head->next;
  node* n = f->next;
  ls->head->next = n;
  n->prev = ls->head;
  free(f);
}
//隨機插入
void listInsert(node* pos, int data)
{
  node* p = pos->prev;
  node* Node = creatNode(data);
  Node->next = pos;
  Node->prev = p;
  p->next = Node;
  pos->prev = Node;
}
//尾刪
void listPopBack(list* ls)
{
  node* last,*p;
  last = ls->head->prev;
  p = last->prev;
  p->next = ls->head;
  ls->head->prev = p;
  free(last);
}
//頭插
void listPushFront(list* ls, int data)
{
  node* f = ls->head->next;
  node* Node = creatNode(data);
  Node->next = f;
  f->prev = Node;
  Node->prev = ls->head;
  ls->head->next = Node;
}
//鏈表刪除pos結點
void listErase(node* pos)
{
  if(pos->next = pos)
  return ;
  node* f = pos->prev;
  node* n = pos->next;
  f->next = n;
  n->prev = f;
  free(pos);
}//鏈表打印
void printList(list* ls)
{
  node* n = ls->head->next;
  while(n!=ls->head)
  {
    printf("%d ",n->data);
    n = n->next;
  }
  printf("\n");
}
//鏈表銷燬
void listDesroy(list* ls)
{
  node* c = ls->head->next;
  while(c!=ls->head)
  {
    node* p =c->next;;
    free(c);
    c = p;
  }
  free(ls->head);
  ls->head = NULL;
}
int main(int argc, char const *argv[]) 
{
  list ls;
  return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章